Documentation
¶
Overview ¶
Package variables implements variables for programming languages similar to those in MetaFont and MetaPost.
Variables are complex things in MetaFont/MetaPost. These are legal:
metafont> showvariable x; x=1 x[]=numeric x[][]=numeric x[][][]=numeric x[][][][]=numeric x[]r=numeric x[]r[]=numeric ...
Identifier-strings are called "tags". In the example above, 'x' is a tag and 'r' is a suffix.
Array variables may be referenced without brackets, if the subscript is just a numeric literal, i.e. x[2]r and x2r refer to the same variable. We do not rely on the parser to decipher these kinds of variable names for us, but rather break up x2r16a => x[2]r[16]a by hand. However, the parser will split up array indices in brackets, for the subscript may be a complex expression ("x[ypart ((8,5) rotated 20)]" is a valid expression in MetaFont). Things are further complicated by the fact that subscripts are allowed to be decimals: x[1.2] is valid, and may be typed "x1.2".
metafont> x[ypart ((8,5) rotated 20)] = 1; ## x7.4347=1
I don't know if this makes sense in practice, but let's try to implement it -- it might be fun!
I did reject some of MetaFont's conventions, however, for the sake of simlicity: Types are inherited from the tag, i.e. if x is of type numeric, then x[2]r is of type numeric, too. This is different from MetaFont, where x2r may be of a different type than x2. Nevertheless, I'll stick to my interpretation, which I find less confusing.
The implementation currently is tightly coupled to the ANTLR V4 parser generator. Using ANTLR vor this task is a bit of overkill. Maybe I'll some day write a recursive descent parser from scratch as a substitute.
BSD License ¶
Copyright (c) 2017, Norbert Pillmayer ¶
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 ¶
- func NewPMMPVarDecl(nm string) runtime.Symbol
- func NewPMMPVarRef(tagName string) runtime.Symbol
- func T() tracing.Trace
- func TypeString(vt VariableType) string
- type PMMPVarDecl
- func (d *PMMPVarDecl) AppendToVarDecl(v *PMMPVarDecl) *PMMPVarDecl
- func (d *PMMPVarDecl) GetBaseType() VariableType
- func (d *PMMPVarDecl) GetFullName() string
- func (d *PMMPVarDecl) GetName() string
- func (d *PMMPVarDecl) ShowDeclarations(s *bytes.Buffer) *bytes.Buffer
- func (d *PMMPVarDecl) String() string
- func (d *PMMPVarDecl) Type() VariableType
- type PMMPVarRef
- func (v *PMMPVarRef) GetFullName() string
- func (v *PMMPVarRef) GetName() string
- func (v *PMMPVarRef) GetSuffixesString() string
- func (v *PMMPVarRef) GetValue() interface{}
- func (v *PMMPVarRef) IsKnown() bool
- func (v *PMMPVarRef) IsPair() bool
- func (v *PMMPVarRef) PullValue()
- func (v *PMMPVarRef) Reincarnate() int
- func (v *PMMPVarRef) SetValue(val interface{})
- func (v *PMMPVarRef) String() string
- func (v *PMMPVarRef) Type() VariableType
- func (v *PMMPVarRef) ValueString() string
- func (v *PMMPVarRef) XPart() *PairPartRef
- func (v *PMMPVarRef) YPart() *PairPartRef
- type PairPartRef
- func (ppart *PairPartRef) GetFirstChild() runtime.TreeNode
- func (ppart *PairPartRef) GetID() int
- func (ppart *PairPartRef) GetName() string
- func (ppart *PairPartRef) GetSibling() runtime.TreeNode
- func (ppart *PairPartRef) GetValue() interface{}
- func (ppart *PairPartRef) IsKnown() bool
- func (ppart *PairPartRef) SetFirstChild(tn runtime.TreeNode)
- func (ppart *PairPartRef) SetSibling(runtime.TreeNode)
- func (ppart *PairPartRef) SetValue(val interface{})
- func (ppart *PairPartRef) Type() VariableType
- type VariableType
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewPMMPVarDecl ¶
Create and initialize a new variable type declaration. This will be passed as a symbol-creator to the symbol table.
func NewPMMPVarRef ¶
Symbol-creator for symbol table: creates tag symbol. Do not use this for pair variables !!
Types ¶
type PMMPVarDecl ¶
type PMMPVarDecl struct { runtime.StdSymbol // to use this we will have to override getName() Parent *PMMPVarDecl // e.g., x <- [] <- suffix(a) BaseTag *PMMPVarDecl // e.g., x // this pointer should never be nil }
MetaFont declares variables explicitly ("numeric x;") or dynamically ("x=1" ⟹ x is of type numeric). Dynamic variable use is permitted for numeric variables only. All other types must be declared. Declaration is for tags only, i.e. the "x" in "x2r". This differs from MetaFont, where x2r can have a separate type from x.
We build up a doubly-linked tree of variable declarations to describe a variable with a single defining tag. The tag is the entity that goes to the symbol table (of a scope). Suffixes and subscripts are attached to the tag, but invisible as symbols.
Example:
numeric x; x2r := 7; x.b := 77;
Result:
tag = "x" of type NumericType ⟹ into symbol table of a scope +-- suffix ".b" of type ComplexSuffix "x.b" +-- subscript "[]" of type ComplexArray: "x[]" +--- suffix ".r" of type ComplexSuffix: "x[].r"
func CreatePMMPVarDecl ¶
func CreatePMMPVarDecl(nm string, tp VariableType, parent *PMMPVarDecl) *PMMPVarDecl
Convenience function to create and initialize a type declaration. Callers provide a (usually complex) type and an optional parent. If the parent is given and already has a child / suffix-partial with the same signature as the one to create, this function will not create a new partial, but provide the existing one.
func (*PMMPVarDecl) AppendToVarDecl ¶
func (d *PMMPVarDecl) AppendToVarDecl(v *PMMPVarDecl) *PMMPVarDecl
Append a complex type partial (suffix or array) to a parent identifier. Will not append the partial, if a partial with this name already exists (as a child).
func (*PMMPVarDecl) GetBaseType ¶
func (d *PMMPVarDecl) GetBaseType() VariableType
Returns the type of the base tag.
func (*PMMPVarDecl) GetFullName ¶
func (d *PMMPVarDecl) GetFullName() string
Get the full name of a type declaration, starting with the base tag. x <- array <- suffix(a) gives "x[].a", which is a bit more verbose than MetaFont's response. I prefer this one.
func (*PMMPVarDecl) GetName ¶
func (d *PMMPVarDecl) GetName() string
Get isolated name of declaration partial (tag, array or suffix).
func (*PMMPVarDecl) ShowDeclarations ¶
func (d *PMMPVarDecl) ShowDeclarations(s *bytes.Buffer) *bytes.Buffer
Show the variable declarations for a tag.
func (*PMMPVarDecl) String ¶
func (d *PMMPVarDecl) String() string
Expressive Stringer implementation.
func (*PMMPVarDecl) Type ¶
func (d *PMMPVarDecl) Type() VariableType
type PMMPVarRef ¶
type PMMPVarRef struct { runtime.StdSymbol // store by normalized name Decl *PMMPVarDecl // type declaration for this variable Value interface{} // if known: has a value (numeric, pair, path, ...) // contains filtered or unexported fields }
Variable reference look like "x", "x2", "hello.world" or "a[4.32].b". Variable references always refer to variable declarations (see code segments above.), which define the type and structure of the variable.
The declaration may have partials of type subscript. For every such partial the reference needs a decimal subscript, which we will store in an array of subscripts.
Example:
x[2.8].b[1] => subscripts = [2.8, 1]
Variable references can have a value (of type interface{}).
func CreatePMMPPairTypeVarRef ¶
func CreatePMMPPairTypeVarRef(decl *PMMPVarDecl, value interface{}, indices []dec.Decimal) *PMMPVarRef
Create a pair variable reference. Low level method.
func CreatePMMPVarRef ¶
func CreatePMMPVarRef(decl *PMMPVarDecl, value interface{}, indices []dec.Decimal) *PMMPVarRef
Create a variable reference. Low level method.
func (*PMMPVarRef) GetFullName ¶
func (v *PMMPVarRef) GetFullName() string
Get the full normalized (canonical) name of a variable, i.e.
"x[2].r".
func (*PMMPVarRef) GetName ¶
func (v *PMMPVarRef) GetName() string
This method returns the full nomalized name, i.e. "x[2].r". This enables us to store the variable in a symbol table. Overrides GetName() of interface Symbol.
func (*PMMPVarRef) GetSuffixesString ¶
func (v *PMMPVarRef) GetSuffixesString() string
Strip the base tag string off of a variable and return all the suffxies as string.
func (*PMMPVarRef) GetValue ¶
func (v *PMMPVarRef) GetValue() interface{}
Interface runtime.Assignable
func (*PMMPVarRef) IsPair ¶
func (v *PMMPVarRef) IsPair() bool
Predicate: is this variable of type pair?
func (*PMMPVarRef) PullValue ¶
func (v *PMMPVarRef) PullValue()
Whenever a pair part (x-part or y-part) is set, it sends a message to the parent pair variable to pull the value. If both parts are known and a numeric value is set, the parent pair creates a combined pair value.
func (*PMMPVarRef) Reincarnate ¶
func (v *PMMPVarRef) Reincarnate() int
Set a new ID for a variable reference. Whenever variables become re-incarnated, a new serial ID is needed. Re-incarnation happens, whenever a variable goes out of scope, but is still relevant in the LEQ-system. The variables' name continues to live on in a new incarnation, while the out-of-scope variable lives on with the old serial.
Returns the old serial ID.
func (*PMMPVarRef) SetValue ¶
func (v *PMMPVarRef) SetValue(val interface{})
Interface runtime.Assignable
func (*PMMPVarRef) String ¶
func (v *PMMPVarRef) String() string
Expressive Stringer implementation.
func (*PMMPVarRef) Type ¶
func (v *PMMPVarRef) Type() VariableType
Type returns the variable's type.
func (*PMMPVarRef) ValueString ¶
func (v *PMMPVarRef) ValueString() string
Get the value of a variable as a string, if known. Otherwise return the tag name or type, depending on the variable type.
func (*PMMPVarRef) XPart ¶
func (v *PMMPVarRef) XPart() *PairPartRef
Get the x-part of a pair variable
func (*PMMPVarRef) YPart ¶
func (v *PMMPVarRef) YPart() *PairPartRef
Get the y-part of a pair variable
type PairPartRef ¶
type PairPartRef struct { Id int // serial ID Pairvar *PMMPVarRef // pair parent Value interface{} // if known: has a value (numeric) }
Variables of type pair will use two sub-symbols for the x-part and y-part of the pair respectively. We will connect them using the sibling-link (x-part) and child-link (y-part) of the PMMPVarRef. Both parts link back to the pair variable.
We need a different serial ID for the y-part, as it will be used as a variable index in a system of linear equations LEQ. Otherwise x-part and y-part would not be distinguishable for the LEQ.
func (*PairPartRef) GetFirstChild ¶
func (ppart *PairPartRef) GetFirstChild() runtime.TreeNode
Filler for interface TreeNode. Never called.
func (*PairPartRef) GetID ¶
func (ppart *PairPartRef) GetID() int
Returns the serial ID for a pair variable's part.
func (*PairPartRef) GetName ¶
func (ppart *PairPartRef) GetName() string
Pair parts (x-part or y-part) return the name of their parent pair symbol, prepending "xpart" or "ypart" respectively. This name is constant and may be used to store the pair part in a symbol table.
func (*PairPartRef) GetSibling ¶
func (ppart *PairPartRef) GetSibling() runtime.TreeNode
Filler for interface TreeNode. Never called.
func (*PairPartRef) GetValue ¶
func (ppart *PairPartRef) GetValue() interface{}
Get the x-part value of a pair.
Interface runtime.Assignable
func (*PairPartRef) SetFirstChild ¶
func (ppart *PairPartRef) SetFirstChild(tn runtime.TreeNode)
Filler for interface TreeNode. Never called.
func (*PairPartRef) SetSibling ¶
func (ppart *PairPartRef) SetSibling(runtime.TreeNode)
Filler for interface TreeNode. Never called.
func (*PairPartRef) SetValue ¶
func (ppart *PairPartRef) SetValue(val interface{})
Interface runtime.Assignable
type VariableType ¶
type VariableType int8
VariableType represents the type of a variable (obviously).
const ( Undefined VariableType = iota NumericType PairType PathType ColorType PenType BoxType FrameType VardefType ComplexArray ComplexSuffix )
Predefined variable types
Directories
¶
Path | Synopsis |
---|---|
Package grammar contains generated Go code produced by ANTLR V4.
|
Package grammar contains generated Go code produced by ANTLR V4. |
Package varparse implements a parser to get variable references from strings.
|
Package varparse implements a parser to get variable references from strings. |