corelang

package
v0.0.0-...-ae32867 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 12, 2020 License: BSD-3-Clause Imports: 13 Imported by: 0

Documentation

Overview

Package corelang implements core commands for DSLs dealing with arithmetic expressions, pairs and paths. It borrows from MetaFont/MetaPost, as described in the accompanying ANTLR grammar file.

Language Features

This package includes functions for numerous language features common to MetaFont-/MetaPost-derivated DSLs.

The implementation is tightly coupled to the ANTLR V4 parser generator. ANTLR is a great tool and I see no use in being independent from it.

Lua Scripting

This package also includes the support for Lua scripting. The DSLs stemming from this language core are Lua-enabled by default.

For further information please refer to types Scripting and LuaVarRef.

BSD License

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of Norbert Pillmayer nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Index

Examples

Constants

This section is empty.

Variables

View Source
var WhateverDeclaration *variables.PMMPVarDecl

Declaration of 'whatever', used to instantiate anonymous whatever-variables.

Functions

func AllocateVariableInMemory

func AllocateVariableInMemory(vref *variables.PMMPVarRef,
	mf *runtime.DynamicMemoryFrame) *variables.PMMPVarRef

Allocate a variable in a memory frame. Existing variable references in this memory frame will be overwritten ! Clients should probably first call FindVariableReferenceInMemory(vref).

func Assign

func Assign(rt *runtime.Runtime, lvalue *variables.PMMPVarRef, e *runtime.ExprNode)

Variable assignment.

assignment : lvalue ASSIGN numtertiary

(1) Retract lvalue from the resolver's table (make a capsule)

(3) Unset the value of lvalue

(3) Re-incarnate lvalue (get a new ID for it)

(4) If type is numeric or pair: Create equation on expression stack, else assign a path value to a path variable.

func Begingroup

func Begingroup(rt *runtime.Runtime, name string) (*runtime.Scope, *runtime.DynamicMemoryFrame)

MetaFont begingroup command: push a new scope and memory frame. Clients may supply a name for the group, otherwise it will be set to "group".

func CallFunc

func CallFunc(val interface{}, fun string, scripting *Scripting) (*runtime.ExprNode, []*variables.PMMPVarRef)

Apply a (math or scripting) function, given by name, to a known/constant argument. Internal math functions are floor(), ceil() and sqrt(). Other function names will be delegated to the scripting subsystem (Lua).

Lua functions will return just one value (of type numeric, pair or path).

func CallVardef

func CallVardef(vref *variables.PMMPVarRef, scripting *Scripting) (*runtime.ExprNode, []*variables.PMMPVarRef)

Call the Lua script for a vardef variable. The parameters of the call will be the suffixes of the variable, i.e. all subscripts and tags after the base tag.

Return values are wrapped into an expression node. If variables are part of the returned expressions, they are packed into an array of variable references.

func CollectVarRefParts

func CollectVarRefParts(rt *runtime.Runtime, t string, children []antlr.Tree) string

Construct a valid variable reference string from parts on the stack.

Collect fragments of a variable reference, e.g. "x[k+1]r". Subscripts should be found on the expression stack and inserted as numeric constants, i.e. resulting in "x[5]r" (if k=4).

Parameter t is the text of the variable ref literal, e.g. "x[k+1]r". It is split by the parser into:

. "x" -> TAG x
. subscript { k+1 }
. "r" -> TAG r

func Declare

Declare a tag to be of type tp.

If the tag is not declared, insert a new symbol in global scope. If a declaration already exists, erase all variables and re-enter a declaration (MetaFont semantics). If the tag has been "saved" in the current or in an outer scope, make this tag a new undefined symbol.

func EncapsulateVariable

func EncapsulateVariable(rt *runtime.Runtime, v *variables.PMMPVarRef)

A variable which goes out of scope becomes a "capsule". We send a message to the expression stack to forget the Symbol(s) for the ID(s) of a variable. Variables are of type numeric or pair.

func EncapsulateVarsInMemory

func EncapsulateVarsInMemory(rt *runtime.Runtime, mf *runtime.DynamicMemoryFrame)

Make all variables in a memory frame "capsules".

When a memory frame is popped from the stack, the local variables living in the frame have to be made "capsules". This is necessary, because they may still be relevant to the LEQ-solver. The LEQ will finally decide when to abondon the "zombie" variable.

func Endgroup

func Endgroup(rt *runtime.Runtime)

MetaFont endgroup command: pop scope and memory frame of group.

func FindVariableReferenceInMemory

func FindVariableReferenceInMemory(rt *runtime.Runtime, vref *variables.PMMPVarRef, doAlloc bool) (
	*variables.PMMPVarRef, *runtime.DynamicMemoryFrame)

Given a variable reference, locate an incarnation in a memory frame. The frame is determined by the variable's declaring scope: search for the top frame linked to the scope.

Variable references live in memory frames. Memory frames correspond to scopes. To find a variable reference -- i.e. a living variable with a possible value -- we have to proceed as follows:

(1) find the variable declaration in a scope, beginning at the top

(2) find the most recent memory frame pointing to this scope

(3) find a variable reference with the correct name in the memory frame

(4) if no reference/incarnation exists, create one

Parameter doAlloc: should step (4) be performed ?

func GetCtxText

func GetCtxText(ctx antlr.Tree) string

I do not always understand ANTLR V4's Go runtime typing and tree semantics (rather poorly documented), so I introduce some helpers. Some of these are probably unnecessary for a better versed ANTLR Go user...

func GetVariableFromExpression

func GetVariableFromExpression(rt *runtime.Runtime, e *runtime.ExprNode) *variables.PMMPVarRef

The expression stack knows nothing about the interpreter's symbols, except the few properties of interface Symbol. The expression stack deals with polynomials and serial IDs of variables. To get back from IDs to variable references, we ask the expression stack for a Symbol (from an ID). If the variable is of type pair, the Symbol may be a pair part (x-part or y-part). Parts point to their parent symbol, thus giving us the variable reference.

func IsTerminal

func IsTerminal(node antlr.Tree) bool

I do not always understand ANTLR V4's Go runtime typing and tree semantics (rather poorly documented), so I introduce some helpers. Some of these are probably unnecessary for a better versed ANTLR Go user...

func LoadBuiltinSymbols

func LoadBuiltinSymbols(rt *runtime.Runtime, scripting *Scripting)

Load builtin symbols into a scope (usually the global scope). Additionally loads initial Lua definitions.

func MakeCanonicalAndResolve

func MakeCanonicalAndResolve(rt *runtime.Runtime, v string, create bool) (
	*variables.PMMPVarRef, error)

Get or create a variable reference. To get the canonical representation of the variable reference, we parse it and construct a small AST. This AST is fed into GetVarRefFromVarSyntax(). The resulting variable reference struct is used to find the memory location of the variable reference.

Example:

vref := MakeCanonicalAndResolve(rt, "a2r", true)
// now vref.String() gives something like:
//      "<var a[2].r=<nil> w/ <decl a[].r/numeric>>"

If a variable has been undeclared and is now created, the top-most scope and memory-frame will hold the newly created variable.

func PopScopeAndMemory

func PopScopeAndMemory(rt *runtime.Runtime) *runtime.DynamicMemoryFrame

Decrease grouping level. We pop the topmost scope and topmost memory frame. This happens after a group is left.

Returns the previously topmost memory frame.

func PushConstant

func PushConstant(rt *runtime.Runtime, vref *variables.PMMPVarRef)

Push a constant (numeric or pair type) onto the expression stack.

func PushVariable

func PushVariable(rt *runtime.Runtime, vref *variables.PMMPVarRef, asLValue bool)

The expression stack knows nothing about the interpreter's symbols, except the few properties of interface Symbol. The expression stack deals with polynomials and serial IDs of variables.

Push a variable (numeric or pair type) onto the expression stack.

func S

func S() tracing.Trace

Trace to the ScriptingTracer

func Save

func Save(rt *runtime.Runtime, tag string)

Save a tag within a group. The tag will be restored at the end of the group. Save-commands within global scope will be ignored. This method simply creates a var decl for the tag in the current scope.

func ScaleDimension

func ScaleDimension(dimen dec.Decimal, unit string) dec.Decimal

Scale a numeric value by a unit.

func Showvariable

func Showvariable(rt *runtime.Runtime, tag string) string

Show all declarations and references for a tag.

func T

func T() tracing.Trace

Trace to the InterpreterTracer

func Unit2numeric

func Unit2numeric(u string) dec.Decimal

TODO complete this. Return scaled points for high level units (cm, mm, pt, in, ...)

func Variable

func Variable(rt *runtime.Runtime, decl *variables.PMMPVarDecl, value interface{},
	subscripts []dec.Decimal, global bool) *variables.PMMPVarRef

Create a variable reference. Parameters are the declaration for the variable, a value and a flag, indicating if this variable should go to global memory. The subscripts parameter is a slice of array-subscripts, if the variable declaration is of array (complex) type.

func Whatever

func Whatever(rt *runtime.Runtime) *variables.PMMPVarRef

Create a whatever anonymous variable. In MetaFont this is a macro, but it is a frequent use case, so we put it in the core.

Types

type DSLRuntimeEnv

type DSLRuntimeEnv struct {
	// contains filtered or unexported fields
}

Lua UserData type for the DSL's interpreter runtime environment. The scripting sub-system has access to variables of the DSL (and therefore access to scopes and memory-frames of the runtime environment).

Example (Lua):

rt = runtime.current                -- find the host-DSL runtime environment
x = rt.connect_variable("x")        -- create a varref (UserData) for tag 'x'
print(x)                            -- print a representation for 'x'
print(x:value())                    -- print the value of 'x'

This will support other host-DSL commands in the future.

type LuaPair

type LuaPair struct {
	X lua.LValue
	Y lua.LValue
}

Lua UserData type for pairs.

Example (Lua):

p = pair.new{2, 5}
print(p:x())          -- get x-part
p:y(3.14)             -- set y-part

type LuaVarRef

type LuaVarRef struct {
	// contains filtered or unexported fields
}

Lua UserData type for variables. Variables reference DSL-variables in the DSL's runtime environment (MetaFont-like variables of type numeric, pair, etc.) A variable may be known or unknown.

Example (Lua):

a = hostlang.numeric("a")   -- connect to a tag of the host language
a[2].r = 3.14               -- assign a numeric value to an 'a'-variable
print(a[2].r:value())       -- prints "3.14"

Variable a[2].r (or short: a2r) is now set/known in the host-language (DSL):

DSL> show a;
## show a;                                    tag=a
a : numeric
a[] : numeric
a[].r : numeric
## a[2].r = 3.14

Lua's notation for (sub-)tables lends itself nicely for a congruency to MetaFont-style variable notations. However, it is not possible to use the DSL shorthand notation ("a2r") for variable names in Lua.

In Lua, there are two member-functions defined for type varref: value() and isknown(). value() is a getter/setter for the variable value. isknown() returns a boolean value.

Example (Lua):

a = hostlang.numeric("a")   -- connect to a tag of the host language
print(a:isknown())          -- prints "false" if not yet defined in the DSL
a:value(3.14)               -- must use this notation for 'a' base tag
print(a:isknown())          -- prints "true"

Variables of this kind are 'live'-objects, i.e. they are always synchronous between the two languages.

func (*LuaVarRef) String

func (lvref *LuaVarRef) String() string

Stringer for variable references. Used for varref.__tostring(...). Will give a debug representation of the DSL-connected variable.

type Scripting

type Scripting struct {
	*lua.LState
	// contains filtered or unexported fields
}

Type Scripting is an opaque data type to provide access to the scripting sub-system.

DSLs built on top of this language core may be scripted with Lua. Lua scripts may be called as hooks or as functions on primary level. Lua functions are preceded by an '@'.

Example:

a2r = 7 + @inlua(x0)

This will delegate to the Lua scripting subsystem, putting the value of x0 onto the Lua stack, and then call Lua-function inlua(...) on it.

Example (Hook)
// Call hook from Go
scripting := NewScripting(nil)
scripting.RegisterHook("echo", func(L *lua.LState) int { // register closure
	lv := L.Get(-1)                                      // get top of stack
	msg := fmt.Sprintf("echo: %s !", lua.LVAsString(lv)) // process
	L.Push(lua.LString(msg))                             // push result
	return 1                                             // return value count
})
r, _ := scripting.CallHook("echo", "hello world") // Lua: echo("hello world")
fmt.Println(r)
Output:

[echo: hello world !]

func NewScripting

func NewScripting(rt *runtime.Runtime) *Scripting

Create a new scripting subsystem. Scripting sub-systems are not thread safe.

func (*Scripting) Call

func (lscript *Scripting) Call(table string, function string, arguments ...interface{}) (
	*ScriptingReturnValues, error)

Call a Lua function, possibly qualified by a table prefix.

func (*Scripting) CallHook

func (lscript *Scripting) CallHook(hook string, arguments ...interface{}) (
	*ScriptingReturnValues, error)

Call a registered hook from Go. Arguments may be passed (Go data types) in a variable argument list. Return values are converted back from Lua types to Go types.

see RegisterHook()

func (*Scripting) Eval

func (lscript *Scripting) Eval(luacmd string, arguments ...interface{}) (*ScriptingReturnValues, error)

Evaluate a Lua statement, given as string. Return arguments (from the Lua stack) are packed into an opaque data structure. The second return value is a possible error condition. The Lua command(s) must be syntactically correct and complete statements (no expressions etc. accepted).

Eval accepts a variable number of untyped arguments. These are put on the Lua stack before the statement is executed.

func (*Scripting) RegisterHook

func (lscript *Scripting) RegisterHook(name string, f lua.LGFunction)

Register a hook function for a key given as string parameter. The hook function must accept a single argument: the Lua state, and return a single int: the number of return values on the Lua stack.

Hooks may be called from the Lua side by name, or from the Go side by CallHook(...).

Example:

scripting := NewScripting()
scripting.RegisterHook("stars", func(L *lua.LState) int {
    L.Push(lua.LString("* * * * *")) // push result
    return 1                         // return value count
})

In Lua:

print(stars())    -- prints "* * * * *" to stdout

type ScriptingReturnValueIterator

type ScriptingReturnValueIterator struct {
	// contains filtered or unexported fields
}

Iterator type for scripting return values. Return values from Lua are wrapped into an opaque type ScriptingReturnValues and accessed using this iterator type.

see ScriptingReturnValues.Iterator()

func (*ScriptingReturnValueIterator) Next

Is there a next scripting argument? Advances the iterator's cursor.

func (*ScriptingReturnValueIterator) Value

func (it *ScriptingReturnValueIterator) Value() (interface{}, variables.VariableType)

Get the value of the scripting argument under the iterator's cursor. Returns the value and a type (see package 'variables' for the definition of variable types).

func (*ScriptingReturnValueIterator) ValueAsExprNode

func (it *ScriptingReturnValueIterator) ValueAsExprNode() (*runtime.ExprNode, []*variables.PMMPVarRef)

Get the value of the scripting argument under the iterator's cursor. Returns the value wrapped in an expression node (or nil). If variables are part of the expression(s), they are returned in a separate array.

type ScriptingReturnValues

type ScriptingReturnValues struct {
	// contains filtered or unexported fields
}

Type to return values from Lua scripts. Single values are accessed with an iterator.

see ScriptingReturnValueIterator

func (*ScriptingReturnValues) Iterator

Create an iterator for scripting arguments / return values.

type TracingErrorListener

type TracingErrorListener struct {
	*antlr.DefaultErrorListener // use default as base class
}

We create our own type of error listener for the ANTLR parser

func (*TracingErrorListener) SyntaxErrorf

func (c *TracingErrorListener) SyntaxErrorf(r antlr.Recognizer, sym interface{},
	line, column int, msg string, e antlr.RecognitionException)

Our error listener prints an error to the trace.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL