Reduced token size
This commit is contained in:
@ -1,6 +1,4 @@
|
||||
package ast
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Node fmt.Stringer
|
||||
type Node any
|
||||
type AST []Node
|
||||
|
@ -8,7 +8,3 @@ import (
|
||||
type Assign struct {
|
||||
Expression *expression.Expression
|
||||
}
|
||||
|
||||
func (node *Assign) String() string {
|
||||
return node.Expression.String()
|
||||
}
|
||||
|
@ -6,7 +6,3 @@ import "git.akyoto.dev/cli/q/src/build/expression"
|
||||
type Call struct {
|
||||
Expression *expression.Expression
|
||||
}
|
||||
|
||||
func (node *Call) String() string {
|
||||
return node.Expression.String()
|
||||
}
|
||||
|
@ -3,31 +3,31 @@ package ast
|
||||
import "git.akyoto.dev/cli/q/src/build/token"
|
||||
|
||||
// Count counts how often the given token appears in the AST.
|
||||
func Count(body AST, kind token.Kind, name string) int {
|
||||
func Count(body AST, buffer []byte, kind token.Kind, name string) int {
|
||||
count := 0
|
||||
|
||||
for _, node := range body {
|
||||
switch node := node.(type) {
|
||||
case *Assign:
|
||||
count += node.Expression.Count(kind, name)
|
||||
count += node.Expression.Count(buffer, kind, name)
|
||||
|
||||
case *Call:
|
||||
count += node.Expression.Count(kind, name)
|
||||
count += node.Expression.Count(buffer, kind, name)
|
||||
|
||||
case *Define:
|
||||
count += node.Value.Count(kind, name)
|
||||
count += node.Value.Count(buffer, kind, name)
|
||||
|
||||
case *Return:
|
||||
if node.Value != nil {
|
||||
count += node.Value.Count(kind, name)
|
||||
count += node.Value.Count(buffer, kind, name)
|
||||
}
|
||||
|
||||
case *If:
|
||||
count += node.Condition.Count(kind, name)
|
||||
count += Count(node.Body, kind, name)
|
||||
count += node.Condition.Count(buffer, kind, name)
|
||||
count += Count(node.Body, buffer, kind, name)
|
||||
|
||||
case *Loop:
|
||||
count += Count(node.Body, kind, name)
|
||||
count += Count(node.Body, buffer, kind, name)
|
||||
|
||||
default:
|
||||
panic("unknown AST type")
|
||||
|
@ -1,8 +1,6 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
)
|
||||
@ -12,7 +10,3 @@ type Define struct {
|
||||
Value *expression.Expression
|
||||
Name token.Token
|
||||
}
|
||||
|
||||
func (node *Define) String() string {
|
||||
return fmt.Sprintf("(= %s %s)", node.Name.Text(), node.Value)
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
)
|
||||
|
||||
@ -11,7 +9,3 @@ type If struct {
|
||||
Condition *expression.Expression
|
||||
Body AST
|
||||
}
|
||||
|
||||
func (node *If) String() string {
|
||||
return fmt.Sprintf("(if %s %s)", node.Condition, node.Body)
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
package ast
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Loop represents a block of repeatable statements.
|
||||
type Loop struct {
|
||||
Body AST
|
||||
}
|
||||
|
||||
func (node *Loop) String() string {
|
||||
return fmt.Sprintf("(loop %s)", node.Body)
|
||||
}
|
||||
|
@ -3,16 +3,15 @@ package ast
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/build/errors"
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
"git.akyoto.dev/cli/q/src/build/keyword"
|
||||
"git.akyoto.dev/cli/q/src/build/token"
|
||||
)
|
||||
|
||||
// Parse generates an AST from a list of tokens.
|
||||
func Parse(tokens token.List) (AST, error) {
|
||||
func Parse(tokens []token.Token, buffer []byte) (AST, error) {
|
||||
tree := make(AST, 0, len(tokens)/64)
|
||||
|
||||
err := EachInstruction(tokens, func(instruction token.List) error {
|
||||
node, err := toASTNode(instruction)
|
||||
node, err := toASTNode(instruction, buffer)
|
||||
|
||||
if err == nil && node != nil {
|
||||
tree = append(tree, node)
|
||||
@ -25,11 +24,9 @@ func Parse(tokens token.List) (AST, error) {
|
||||
}
|
||||
|
||||
// toASTNode generates an AST node from an instruction.
|
||||
func toASTNode(tokens token.List) (Node, error) {
|
||||
if tokens[0].Kind == token.Keyword {
|
||||
word := tokens[0].Text()
|
||||
|
||||
if word == keyword.Return {
|
||||
func toASTNode(tokens token.List, buffer []byte) (Node, error) {
|
||||
if tokens[0].IsKeyword() {
|
||||
if tokens[0].Kind == token.Return {
|
||||
if len(tokens) == 1 {
|
||||
return &Return{}, nil
|
||||
}
|
||||
@ -38,7 +35,7 @@ func toASTNode(tokens token.List) (Node, error) {
|
||||
return &Return{Value: value}, nil
|
||||
}
|
||||
|
||||
if keywordHasBlock(word) {
|
||||
if keywordHasBlock(tokens[0].Kind) {
|
||||
blockStart := tokens.IndexKind(token.BlockStart)
|
||||
blockEnd := tokens.LastIndexKind(token.BlockEnd)
|
||||
|
||||
@ -50,19 +47,19 @@ func toASTNode(tokens token.List) (Node, error) {
|
||||
return nil, errors.New(errors.MissingBlockEnd, nil, tokens[len(tokens)-1].End())
|
||||
}
|
||||
|
||||
body, err := Parse(tokens[blockStart+1 : blockEnd])
|
||||
body, err := Parse(tokens[blockStart+1:blockEnd], buffer)
|
||||
|
||||
switch word {
|
||||
case keyword.If:
|
||||
switch tokens[0].Kind {
|
||||
case token.If:
|
||||
condition := expression.Parse(tokens[1:blockStart])
|
||||
return &If{Condition: condition, Body: body}, err
|
||||
|
||||
case keyword.Loop:
|
||||
case token.Loop:
|
||||
return &Loop{Body: body}, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(&errors.KeywordNotImplemented{Keyword: word}, nil, tokens[0].Position)
|
||||
return nil, errors.New(&errors.KeywordNotImplemented{Keyword: tokens[0].Text(buffer)}, nil, tokens[0].Position)
|
||||
}
|
||||
|
||||
expr := expression.Parse(tokens)
|
||||
@ -92,26 +89,26 @@ func toASTNode(tokens token.List) (Node, error) {
|
||||
return &Call{Expression: expr}, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text()}, nil, expr.Token.Position)
|
||||
return nil, errors.New(&errors.InvalidInstruction{Instruction: expr.Token.Text(buffer)}, nil, expr.Token.Position)
|
||||
}
|
||||
}
|
||||
|
||||
// IsAssignment returns true if the expression is an assignment.
|
||||
func IsAssignment(expr *expression.Expression) bool {
|
||||
return expr.Token.Kind == token.Operator && expr.Token.Bytes[len(expr.Token.Bytes)-1] == '='
|
||||
return expr.Token.IsAssignment()
|
||||
}
|
||||
|
||||
// IsFunctionCall returns true if the expression is a function call.
|
||||
func IsFunctionCall(expr *expression.Expression) bool {
|
||||
return expr.Token.Kind == token.Operator && expr.Token.Text() == "λ"
|
||||
return expr.Token.Kind == token.Call
|
||||
}
|
||||
|
||||
// IsVariableDefinition returns true if the expression is a variable definition.
|
||||
func IsVariableDefinition(expr *expression.Expression) bool {
|
||||
return expr.Token.Kind == token.Operator && expr.Token.Text() == ":="
|
||||
return expr.Token.Kind == token.Define
|
||||
}
|
||||
|
||||
// keywordHasBlock returns true if the keyword requires a block.
|
||||
func keywordHasBlock(word string) bool {
|
||||
return word == keyword.If || word == keyword.Loop
|
||||
func keywordHasBlock(kind token.Kind) bool {
|
||||
return kind == token.If || kind == token.Loop
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.akyoto.dev/cli/q/src/build/expression"
|
||||
)
|
||||
|
||||
@ -10,7 +8,3 @@ import (
|
||||
type Return struct {
|
||||
Value *expression.Expression
|
||||
}
|
||||
|
||||
func (node *Return) String() string {
|
||||
return fmt.Sprintf("(return %s)", node.Value)
|
||||
}
|
||||
|
Reference in New Issue
Block a user