158 lines
2.6 KiB
Go

package expression
import (
"math"
"git.akyoto.dev/cli/q/src/build/token"
)
var call = []byte("λ")
// Parse generates an expression tree from tokens.
func Parse(tokens token.List) *Expression {
var (
cursor *Expression
root *Expression
groupLevel = 0
groupPosition = 0
)
for i, t := range tokens {
if t.Kind == token.GroupStart {
groupLevel++
if groupLevel == 1 {
groupPosition = i + 1
}
continue
}
if t.Kind == token.GroupEnd {
groupLevel--
if groupLevel != 0 {
continue
}
isFunctionCall := isComplete(cursor)
if isFunctionCall {
parameters := NewList(tokens[groupPosition:i])
node := New()
node.Token.Kind = token.Operator
node.Token.Position = tokens[groupPosition].Position
node.Token.Bytes = call
node.Precedence = precedence("λ")
if cursor.Token.Kind == token.Operator && node.Precedence > cursor.Precedence {
cursor.LastChild().Replace(node)
} else {
if cursor == root {
root = node
}
cursor.Replace(node)
}
for _, param := range parameters {
node.AddChild(param)
}
cursor = node
continue
}
group := Parse(tokens[groupPosition:i])
if group == nil {
continue
}
group.Precedence = math.MaxInt8
if cursor == nil {
cursor = group
root = group
} else {
cursor.AddChild(group)
}
continue
}
if groupLevel > 0 {
continue
}
if t.Kind == token.Identifier || t.Kind == token.Number || t.Kind == token.String {
if cursor != nil {
node := NewLeaf(t)
cursor.AddChild(node)
} else {
cursor = NewLeaf(t)
root = cursor
}
continue
}
if t.Kind == token.Operator {
if cursor == nil {
cursor = NewLeaf(t)
cursor.Precedence = precedence(t.Text())
root = cursor
continue
}
node := NewLeaf(t)
node.Precedence = precedence(t.Text())
if cursor.Token.Kind == token.Operator {
oldPrecedence := cursor.Precedence
newPrecedence := node.Precedence
if newPrecedence > oldPrecedence {
cursor.LastChild().Replace(node)
} else {
start := cursor
for start != nil {
precedence := start.Precedence
if precedence < newPrecedence {
start.LastChild().Replace(node)
break
}
if precedence == newPrecedence {
if start == root {
root = node
}
start.Replace(node)
break
}
start = start.Parent
}
if start == nil {
root.Replace(node)
root = node
}
}
} else {
node.AddChild(cursor)
root = node
}
cursor = node
continue
}
}
return root
}