166 lines
2.8 KiB
Go
166 lines
2.8 KiB
Go
package expression
|
|
|
|
import (
|
|
"math"
|
|
|
|
"git.akyoto.dev/cli/q/src/token"
|
|
)
|
|
|
|
// Parse generates an expression tree from tokens.
|
|
func Parse(tokens []token.Token) *Expression {
|
|
var (
|
|
cursor *Expression
|
|
root *Expression
|
|
groupLevel = 0
|
|
groupPosition = 0
|
|
)
|
|
|
|
for i, t := range tokens {
|
|
if t.Kind == token.GroupStart || t.Kind == token.ArrayStart {
|
|
groupLevel++
|
|
|
|
if groupLevel == 1 {
|
|
groupPosition = i + 1
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
if t.Kind == token.GroupEnd || t.Kind == token.ArrayEnd {
|
|
groupLevel--
|
|
|
|
if groupLevel != 0 {
|
|
continue
|
|
}
|
|
|
|
// Function call or array access
|
|
if isComplete(cursor) {
|
|
parameters := NewList(tokens[groupPosition:i])
|
|
|
|
node := New()
|
|
node.Token.Position = tokens[groupPosition].Position
|
|
|
|
switch t.Kind {
|
|
case token.GroupEnd:
|
|
node.Token.Kind = token.Call
|
|
case token.ArrayEnd:
|
|
node.Token.Kind = token.Array
|
|
}
|
|
|
|
node.Precedence = precedence(node.Token.Kind)
|
|
|
|
if cursor.Token.IsOperator() && 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 || t.Kind == token.Rune {
|
|
if cursor != nil {
|
|
node := NewLeaf(t)
|
|
cursor.AddChild(node)
|
|
} else {
|
|
cursor = NewLeaf(t)
|
|
root = cursor
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
if !t.IsOperator() {
|
|
continue
|
|
}
|
|
|
|
if cursor == nil {
|
|
cursor = NewLeaf(t)
|
|
cursor.Precedence = precedence(t.Kind)
|
|
root = cursor
|
|
continue
|
|
}
|
|
|
|
node := NewLeaf(t)
|
|
node.Precedence = precedence(t.Kind)
|
|
|
|
if cursor.Token.IsOperator() {
|
|
oldPrecedence := cursor.Precedence
|
|
newPrecedence := node.Precedence
|
|
|
|
if newPrecedence > oldPrecedence {
|
|
if len(cursor.Children) == numOperands(cursor.Token.Kind) {
|
|
cursor.LastChild().Replace(node)
|
|
} else {
|
|
cursor.AddChild(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
|
|
}
|
|
|
|
return root
|
|
}
|