158 lines
2.6 KiB
Go
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
|
|
}
|