751 lines
12 KiB
Go
751 lines
12 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"math/big"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type NodeType int
|
|
|
|
type Node interface {
|
|
Type() NodeType
|
|
String() string
|
|
|
|
Bounds() (Pos, Pos)
|
|
}
|
|
|
|
type Bounded interface {
|
|
Bounds() (Pos, Pos)
|
|
}
|
|
|
|
const (
|
|
StringNodeType NodeType = iota
|
|
FloatNodeType
|
|
IntegerNodeType
|
|
ReferenceNodeType
|
|
BooleanNodeType
|
|
NilNodeType
|
|
ListNodeType
|
|
TupleNodeType
|
|
BinaryNodeType
|
|
UnaryNodeType
|
|
BlockNodeType
|
|
ConditionalNodeType
|
|
LoopNodeType
|
|
ForNodeType
|
|
AssignNodeType
|
|
InvokeNodeType
|
|
CallNodeType
|
|
FunctionNodeType
|
|
ReturnNodeType
|
|
AccessNodeType
|
|
AliasNodeType
|
|
IndexNodeType
|
|
IncludeNodeType
|
|
BreakpointNodeType
|
|
)
|
|
|
|
func (n NodeType) String() string {
|
|
switch n {
|
|
case StringNodeType:
|
|
return "String"
|
|
case FloatNodeType:
|
|
return "Float"
|
|
case IntegerNodeType:
|
|
return "Integer"
|
|
case ReferenceNodeType:
|
|
return "Reference"
|
|
case BinaryNodeType:
|
|
return "Binary"
|
|
case BooleanNodeType:
|
|
return "Boolean"
|
|
case NilNodeType:
|
|
return "Nil"
|
|
case BlockNodeType:
|
|
return "Block"
|
|
case ConditionalNodeType:
|
|
return "Conditional"
|
|
case LoopNodeType:
|
|
return "Loop"
|
|
case AssignNodeType:
|
|
return "Assign"
|
|
case InvokeNodeType:
|
|
return "Invoke"
|
|
case FunctionNodeType:
|
|
return "Function"
|
|
case ReturnNodeType:
|
|
return "Return"
|
|
case ListNodeType:
|
|
return "List"
|
|
case TupleNodeType:
|
|
return "Tuple"
|
|
case AccessNodeType:
|
|
return "Access"
|
|
case BreakpointNodeType:
|
|
return "Breakpoint"
|
|
case UnaryNodeType:
|
|
return "Unary"
|
|
case CallNodeType:
|
|
return "Call"
|
|
case AliasNodeType:
|
|
return "Alias"
|
|
case IndexNodeType:
|
|
return "Index"
|
|
}
|
|
return "Invalid Node Type"
|
|
}
|
|
|
|
// ReferenceNode a reference to a variable on the stack
|
|
type ReferenceNode struct {
|
|
name string
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n ReferenceNode) Type() NodeType {
|
|
return ReferenceNodeType
|
|
}
|
|
|
|
func (n ReferenceNode) String() string {
|
|
return n.name
|
|
}
|
|
|
|
func (n ReferenceNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// StringNode string/text values
|
|
type StringNode struct {
|
|
value string
|
|
quoted string
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n StringNode) Type() NodeType {
|
|
return StringNodeType
|
|
}
|
|
|
|
func (n StringNode) String() string {
|
|
return n.quoted
|
|
}
|
|
|
|
func (n StringNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type FloatNode struct {
|
|
value float64
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n FloatNode) Type() NodeType {
|
|
return FloatNodeType
|
|
}
|
|
|
|
func (n FloatNode) String() string {
|
|
return strconv.FormatFloat(n.value, 'g', -1, FloatSize)
|
|
}
|
|
|
|
func (n FloatNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type IntegerNode struct {
|
|
value *big.Int
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n IntegerNode) Type() NodeType {
|
|
return IntegerNodeType
|
|
}
|
|
|
|
func (n IntegerNode) String() string {
|
|
return n.value.String()
|
|
}
|
|
|
|
func (n IntegerNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// ListNode a list or sequence of values (items)
|
|
type ListNode struct {
|
|
items []Node
|
|
content TypeSignature
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n ListNode) Type() NodeType {
|
|
return ListNodeType
|
|
}
|
|
|
|
func (n ListNode) String() string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
for i, item := range n.items {
|
|
if i > 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
sb.WriteString(item.String())
|
|
}
|
|
sb.WriteString("]")
|
|
return sb.String()
|
|
}
|
|
|
|
func (n ListNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type TupleNode struct {
|
|
items []Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n TupleNode) Type() NodeType {
|
|
return TupleNodeType
|
|
}
|
|
|
|
func (n TupleNode) String() string {
|
|
sb := strings.Builder{}
|
|
|
|
sb.WriteString("(")
|
|
for i, item := range n.items {
|
|
if i > 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
|
|
sb.WriteString(item.String())
|
|
}
|
|
sb.WriteString(")")
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
func (n TupleNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type AccessNode struct {
|
|
source Node
|
|
property *Token
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n AccessNode) Type() NodeType {
|
|
return AccessNodeType
|
|
}
|
|
|
|
func (n AccessNode) String() string {
|
|
return fmt.Sprintf("(%s from %s)", n.property.Lexeme, n.source)
|
|
}
|
|
|
|
func (n AccessNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type BinaryOperation uint
|
|
|
|
func (n BinaryOperation) String() string {
|
|
switch n {
|
|
case BinaryAddition:
|
|
return "add"
|
|
case BinarySubtraction:
|
|
return "subtract"
|
|
case BinaryMultiplication:
|
|
return "multiply"
|
|
case BinaryDivision:
|
|
return "divide"
|
|
case BinaryEquality:
|
|
return "equality"
|
|
case BinaryInequality:
|
|
return "inequality"
|
|
case BinaryLess:
|
|
return "less"
|
|
case BinaryGreater:
|
|
return "greater"
|
|
case BinaryLessEqual:
|
|
return "less or equal"
|
|
case BinaryGreaterEqual:
|
|
return "greater or equal"
|
|
case BinaryBooleanAnd:
|
|
return "and"
|
|
case BinaryBooleanOr:
|
|
return "or"
|
|
}
|
|
|
|
return "undefined arithmetic operation"
|
|
}
|
|
|
|
const (
|
|
BinaryAddition BinaryOperation = iota
|
|
BinarySubtraction
|
|
BinaryMultiplication
|
|
BinaryDivision
|
|
BinaryModulo
|
|
|
|
BinaryBooleanAnd
|
|
BinaryBooleanOr
|
|
|
|
// Comparison
|
|
BinaryEquality
|
|
BinaryInequality
|
|
BinaryLess
|
|
BinaryGreater
|
|
BinaryLessEqual
|
|
BinaryGreaterEqual
|
|
)
|
|
|
|
func (n BinaryOperation) Symbol() string {
|
|
switch n {
|
|
case BinaryAddition:
|
|
return "+"
|
|
case BinarySubtraction:
|
|
return "-"
|
|
case BinaryMultiplication:
|
|
return "*"
|
|
case BinaryDivision:
|
|
return "/"
|
|
case BinaryModulo:
|
|
return "%"
|
|
case BinaryEquality:
|
|
return "=="
|
|
case BinaryInequality:
|
|
return "!="
|
|
case BinaryLess:
|
|
return "<"
|
|
case BinaryGreater:
|
|
return ">"
|
|
case BinaryLessEqual:
|
|
return "<="
|
|
case BinaryGreaterEqual:
|
|
return ">="
|
|
case BinaryBooleanAnd:
|
|
return "&&"
|
|
case BinaryBooleanOr:
|
|
return "||"
|
|
}
|
|
|
|
panic("unsupported binary operation to symbol conversion for " + n.String())
|
|
}
|
|
|
|
// BinaryNode All operations which take 2 variables
|
|
type BinaryNode struct {
|
|
BinaryOperation
|
|
Left Node
|
|
Right Node
|
|
|
|
operator *Token
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n BinaryNode) Type() NodeType {
|
|
return BinaryNodeType
|
|
}
|
|
|
|
func (n BinaryNode) String() string {
|
|
return fmt.Sprintf("%s %s %s", n.Left.String(), n.BinaryOperation.String(), n.Right.String())
|
|
}
|
|
|
|
func (n BinaryNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type UnaryOperation int
|
|
|
|
const (
|
|
UnaryNegate UnaryOperation = iota
|
|
UnaryNot
|
|
)
|
|
|
|
func (op UnaryOperation) String() string {
|
|
switch op {
|
|
case UnaryNegate:
|
|
return "negate"
|
|
case UnaryNot:
|
|
return "not"
|
|
}
|
|
|
|
panic("unimplemented unary operation to string conversion")
|
|
}
|
|
|
|
func (op UnaryOperation) Symbol() string {
|
|
switch op {
|
|
case UnaryNegate:
|
|
return "-"
|
|
case UnaryNot:
|
|
return "!"
|
|
}
|
|
|
|
panic("unimplemented unary operation to symbol conversion")
|
|
}
|
|
|
|
type UnaryNode struct {
|
|
UnaryOperation
|
|
value Node
|
|
|
|
operator *Token
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n UnaryNode) Type() NodeType {
|
|
return UnaryNodeType
|
|
}
|
|
|
|
func (n UnaryNode) String() string {
|
|
return fmt.Sprintf("%s %s", n.UnaryOperation.String(), n.value.String())
|
|
}
|
|
|
|
func (n UnaryNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// BooleanNode boolean value
|
|
type BooleanNode struct {
|
|
Boolean bool
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n BooleanNode) Type() NodeType {
|
|
return BooleanNodeType
|
|
}
|
|
|
|
func (n BooleanNode) String() string {
|
|
return strconv.FormatBool(n.Boolean)
|
|
}
|
|
|
|
func (n BooleanNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// NilNode nil value
|
|
type NilNode struct {
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n NilNode) Type() NodeType {
|
|
return NilNodeType
|
|
}
|
|
|
|
func (n NilNode) String() string {
|
|
return "nil"
|
|
}
|
|
|
|
func (n NilNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// BlockNode block node with statements
|
|
type BlockNode struct {
|
|
statements []Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n BlockNode) Type() NodeType {
|
|
return BlockNodeType
|
|
}
|
|
|
|
func (n BlockNode) String() string {
|
|
builder := strings.Builder{}
|
|
|
|
for _, stmt := range n.statements {
|
|
builder.WriteString(stmt.String())
|
|
builder.WriteString("\n")
|
|
}
|
|
|
|
return builder.String()
|
|
}
|
|
|
|
func (n BlockNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// ConditionalNode conditionals (if statements)
|
|
type ConditionalNode struct {
|
|
condition Node
|
|
do Node
|
|
otherwise Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n ConditionalNode) Type() NodeType {
|
|
return ConditionalNodeType
|
|
}
|
|
|
|
func (n ConditionalNode) String() string {
|
|
if n.otherwise == nil {
|
|
return fmt.Sprintf("if %s then %s", n.condition.String(), n.do.String())
|
|
}
|
|
|
|
return fmt.Sprintf("if %s then %s otheriwise %s", n.condition.String(), n.do.String(), n.otherwise.String())
|
|
}
|
|
|
|
func (n ConditionalNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// LoopNode While loops
|
|
type LoopNode struct {
|
|
condition Node
|
|
do Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n LoopNode) Type() NodeType {
|
|
return LoopNodeType
|
|
}
|
|
|
|
func (n LoopNode) String() string {
|
|
return fmt.Sprintf("while %s loop %s", n.condition.String(), n.do.String())
|
|
}
|
|
|
|
func (n LoopNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// ForNode For loops
|
|
type ForNode struct {
|
|
counter Node
|
|
iterator Node
|
|
logic Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n ForNode) Type() NodeType {
|
|
return ForNodeType
|
|
}
|
|
|
|
func (n ForNode) String() string {
|
|
return fmt.Sprintf("for %s in %s; %s", n.counter, n.iterator, n.logic)
|
|
}
|
|
|
|
func (n ForNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// AssignNode assignment
|
|
type AssignNode struct {
|
|
dest Node
|
|
value Node
|
|
declare bool
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n AssignNode) Type() NodeType {
|
|
return AssignNodeType
|
|
}
|
|
|
|
func (n AssignNode) String() string {
|
|
return fmt.Sprintf("set %s to %s", n.dest, n.value)
|
|
}
|
|
|
|
func (n AssignNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// InvokeNode function call
|
|
type InvokeNode struct {
|
|
source Node
|
|
args []Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n InvokeNode) Type() NodeType {
|
|
return InvokeNodeType
|
|
}
|
|
|
|
func (n InvokeNode) String() string {
|
|
return fmt.Sprintf("invoke %s with args (%s)", n.source.String(), n.args)
|
|
}
|
|
|
|
func (n InvokeNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// CallNode call a function of a value
|
|
type CallNode struct {
|
|
source Node
|
|
name *Token
|
|
args []Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n CallNode) Type() NodeType {
|
|
return CallNodeType
|
|
}
|
|
|
|
func (n CallNode) String() string {
|
|
return fmt.Sprintf("call %s on %s with args (%s)", n.name, n.source.String(), n.args)
|
|
}
|
|
|
|
func (n CallNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
// FunctionNode definition of function
|
|
type FunctionNode struct {
|
|
name string
|
|
parameters []FunctionParameter
|
|
yield TypeSignature
|
|
logic Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
type FunctionParameter struct {
|
|
Name string
|
|
Signature TypeSignature
|
|
}
|
|
|
|
func (n FunctionNode) Type() NodeType {
|
|
return FunctionNodeType
|
|
}
|
|
|
|
func (n FunctionNode) String() string {
|
|
return fmt.Sprintf("definition of %s, do %s", n.name, n.logic.String())
|
|
}
|
|
|
|
func (n FunctionNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
func (n FunctionNode) Signature() *FunctionSignature {
|
|
args := make([]TypeSignature, len(n.parameters))
|
|
for i, p := range n.parameters {
|
|
args[i] = p.Signature
|
|
}
|
|
|
|
return &FunctionSignature{
|
|
args,
|
|
n.yield,
|
|
}
|
|
}
|
|
|
|
// ReturnNode return a value out of this context
|
|
type ReturnNode struct {
|
|
value Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n ReturnNode) Type() NodeType {
|
|
return ReturnNodeType
|
|
}
|
|
|
|
func (n ReturnNode) String() string {
|
|
return fmt.Sprintf("return %s", n.value)
|
|
}
|
|
|
|
func (n ReturnNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type AliasNode struct {
|
|
name *Token
|
|
signature TypeSignature
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n AliasNode) Type() NodeType {
|
|
return AliasNodeType
|
|
}
|
|
|
|
func (n AliasNode) String() string {
|
|
return fmt.Sprintf("alias %s to be %s", n.name, n.signature)
|
|
}
|
|
|
|
func (n AliasNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type IncludeNode struct {
|
|
path *StringNode
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n IncludeNode) Type() NodeType {
|
|
return IncludeNodeType
|
|
}
|
|
|
|
func (n IncludeNode) String() string {
|
|
return fmt.Sprintf("include \"%s\"", n.path)
|
|
}
|
|
|
|
func (n IncludeNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type IndexNode struct {
|
|
source Node
|
|
index Node
|
|
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n IndexNode) Type() NodeType {
|
|
return IndexNodeType
|
|
}
|
|
|
|
func (n IndexNode) String() string {
|
|
return fmt.Sprintf("index %s of %s", n.source.String(), n.index)
|
|
}
|
|
|
|
func (n IndexNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|
|
|
|
type BreakpointNode struct {
|
|
start Pos
|
|
end Pos
|
|
}
|
|
|
|
func (n BreakpointNode) Type() NodeType {
|
|
return BreakpointNodeType
|
|
}
|
|
|
|
func (n BreakpointNode) String() string {
|
|
return "breakpoint"
|
|
}
|
|
|
|
func (n BreakpointNode) Bounds() (Pos, Pos) {
|
|
return n.start, n.end
|
|
}
|