Simplified file structure
This commit is contained in:
165
src/expression/Parse.go
Normal file
165
src/expression/Parse.go
Normal file
@ -0,0 +1,165 @@
|
||||
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
|
||||
}
|
Reference in New Issue
Block a user