anglais/core/nodes.go
neemek 42fa039daf
All checks were successful
/ test (push) Successful in 50s
basic records support
2026-08-17 17:08:24 +02:00

786 lines
13 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
RecordNodeType
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"
case RecordNodeType:
return "Record"
}
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 RecordNode struct {
entries map[string]Node
start Pos
end Pos
}
func (n RecordNode) Type() NodeType {
return RecordNodeType
}
func (n RecordNode) String() string {
sb := strings.Builder{}
sb.WriteString("(")
for name, item := range n.entries {
sb.WriteString(name)
sb.WriteString(": ")
sb.WriteString(item.String())
sb.WriteString(",")
}
sb.WriteString(")")
return sb.String()
}
func (n RecordNode) 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 BinaryModulo:
return "modulo"
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
}