Implemented source tracking and type checking
All checks were successful
/ test (push) Successful in 21s
All checks were successful
/ test (push) Successful in 21s
This commit is contained in:
parent
70c2da4a4d
commit
329fcfff6f
30 changed files with 427 additions and 125 deletions
|
@ -6,6 +6,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/build"
|
"git.urbach.dev/cli/q/src/build"
|
||||||
"git.urbach.dev/cli/q/src/core"
|
"git.urbach.dev/cli/q/src/core"
|
||||||
"git.urbach.dev/cli/q/src/scanner"
|
"git.urbach.dev/cli/q/src/scanner"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compile waits for the scan to finish and compiles all functions.
|
// Compile waits for the scan to finish and compiles all functions.
|
||||||
|
@ -16,13 +17,43 @@ func Compile(b *build.Build) (*core.Environment, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for existence of `init`
|
||||||
|
init, exists := all.Functions["core.init"]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, MissingInitFunction
|
||||||
|
}
|
||||||
|
|
||||||
// Check for existence of `main`
|
// Check for existence of `main`
|
||||||
_, exists := all.Functions["main.main"]
|
_, exists = all.Functions["main.main"]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, MissingMainFunction
|
return nil, MissingMainFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve types
|
||||||
|
for _, f := range all.Functions {
|
||||||
|
f.Type = &types.Function{
|
||||||
|
Input: make([]types.Type, len(f.Input)),
|
||||||
|
Output: make([]types.Type, len(f.Output)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, input := range f.Input {
|
||||||
|
input.Typ = types.Parse(input.Source[1:], f.File.Bytes)
|
||||||
|
f.Type.Input[i] = input.Typ
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, output := range f.Output {
|
||||||
|
if len(output.Source) > 1 {
|
||||||
|
output.Typ = types.Parse(output.Source[1:], f.File.Bytes)
|
||||||
|
} else {
|
||||||
|
output.Typ = types.Parse(output.Source, f.File.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Type.Output[i] = output.Typ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compileFunctions(maps.Values(all.Functions))
|
compileFunctions(maps.Values(all.Functions))
|
||||||
|
|
||||||
for _, f := range all.Functions {
|
for _, f := range all.Functions {
|
||||||
|
@ -32,7 +63,7 @@ func Compile(b *build.Build) (*core.Environment, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.ShowSSA {
|
if b.ShowSSA {
|
||||||
showSSA(maps.Values(all.Functions))
|
showSSA(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
return all, nil
|
return all, nil
|
||||||
|
|
|
@ -3,5 +3,6 @@ package compiler
|
||||||
import "git.urbach.dev/cli/q/src/errors"
|
import "git.urbach.dev/cli/q/src/errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
MissingInitFunction = errors.String("Missing init function")
|
||||||
MissingMainFunction = errors.String("Missing main function")
|
MissingMainFunction = errors.String("Missing main function")
|
||||||
)
|
)
|
|
@ -2,16 +2,15 @@ package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"iter"
|
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/core"
|
"git.urbach.dev/cli/q/src/core"
|
||||||
"git.urbach.dev/go/color/ansi"
|
"git.urbach.dev/go/color/ansi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// showSSA shows the SSA IR.
|
// showSSA shows the SSA IR.
|
||||||
func showSSA(functions iter.Seq[*core.Function]) {
|
func showSSA(root *core.Function) {
|
||||||
for f := range functions {
|
root.EachDependency(make(map[*core.Function]bool), func(f *core.Function) {
|
||||||
ansi.Bold.Printf("%s:\n", f.UniqueName)
|
ansi.Yellow.Printf("%s:\n", f.UniqueName)
|
||||||
|
|
||||||
for i, block := range f.Blocks {
|
for i, block := range f.Blocks {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
|
@ -19,8 +18,13 @@ func showSSA(functions iter.Seq[*core.Function]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, instr := range block.Instructions {
|
for i, instr := range block.Instructions {
|
||||||
fmt.Printf("t%d = %s\n", i, instr.String())
|
ansi.Dim.Printf("%-4d", i)
|
||||||
}
|
fmt.Printf("%-40s", instr.String())
|
||||||
|
ansi.Cyan.Printf("%-30s", instr.Type().Name())
|
||||||
|
ansi.Dim.Printf("%s\n", f.File.Bytes[instr.Start():instr.End()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
})
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ import (
|
||||||
func (f *Function) CheckDeadCode() error {
|
func (f *Function) CheckDeadCode() error {
|
||||||
for instr := range f.Values {
|
for instr := range f.Values {
|
||||||
if instr.IsConst() && instr.Alive() == 0 {
|
if instr.IsConst() && instr.Alive() == 0 {
|
||||||
return errors.New(&UnusedValue{Value: instr.String()}, f.File, instr.Token().Position)
|
return errors.New(&UnusedValue{Value: instr.String()}, f.File, instr.Start())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/asm"
|
"git.urbach.dev/cli/q/src/asm"
|
||||||
"git.urbach.dev/cli/q/src/cpu"
|
"git.urbach.dev/cli/q/src/cpu"
|
||||||
"git.urbach.dev/cli/q/src/ssa"
|
"git.urbach.dev/cli/q/src/ssa"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Compile turns a function into machine code.
|
// Compile turns a function into machine code.
|
||||||
|
@ -18,12 +18,35 @@ func (f *Function) Compile() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Identifiers[input.Name] = f.AppendRegister(i + extra)
|
array, isArray := input.Typ.(*types.Array)
|
||||||
|
|
||||||
if input.TypeTokens[0].Kind == token.ArrayStart {
|
if isArray {
|
||||||
extra++
|
pointer := &ssa.Parameter{
|
||||||
f.Identifiers[input.Name+".length"] = f.AppendRegister(i + extra)
|
Index: uint8(i + extra),
|
||||||
|
Name: input.Name,
|
||||||
|
Typ: &types.Pointer{To: array.Of},
|
||||||
|
Source: input.Source,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Append(pointer)
|
||||||
|
f.Identifiers[pointer.Name] = pointer
|
||||||
|
extra++
|
||||||
|
|
||||||
|
length := &ssa.Parameter{
|
||||||
|
Index: uint8(i + extra),
|
||||||
|
Name: input.Name + ".len",
|
||||||
|
Typ: types.AnyInt,
|
||||||
|
Source: input.Source,
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Append(length)
|
||||||
|
f.Identifiers[length.Name] = length
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
input.Index = uint8(i + extra)
|
||||||
|
f.Append(input)
|
||||||
|
f.Identifiers[input.Name] = input
|
||||||
}
|
}
|
||||||
|
|
||||||
for instr := range f.Body.Instructions {
|
for instr := range f.Body.Instructions {
|
||||||
|
@ -49,15 +72,15 @@ func (f *Function) Compile() {
|
||||||
for instr := range f.Values {
|
for instr := range f.Values {
|
||||||
switch instr := instr.(type) {
|
switch instr := instr.(type) {
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
f.mv(instr.Args[1:], f.CPU.Call)
|
f.mv(instr.Arguments[1:], f.CPU.Call)
|
||||||
|
|
||||||
switch arg := instr.Args[0].(type) {
|
switch arg := instr.Arguments[0].(type) {
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
f.Assembler.Instructions = append(f.Assembler.Instructions, &asm.Call{Label: arg.UniqueName})
|
f.Assembler.Instructions = append(f.Assembler.Instructions, &asm.Call{Label: arg.UniqueName})
|
||||||
}
|
}
|
||||||
|
|
||||||
case *ssa.Syscall:
|
case *ssa.Syscall:
|
||||||
f.mv(instr.Args, f.CPU.Syscall)
|
f.mv(instr.Arguments, f.CPU.Syscall)
|
||||||
f.Assembler.Append(&asm.Syscall{})
|
f.Assembler.Append(&asm.Syscall{})
|
||||||
|
|
||||||
case *ssa.Return:
|
case *ssa.Return:
|
||||||
|
|
|
@ -16,9 +16,8 @@ func (f *Function) CompileReturn(tokens token.List) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Append(&ssa.Return{
|
f.Append(&ssa.Return{
|
||||||
Arguments: ssa.Arguments{
|
Arguments: []ssa.Value{value},
|
||||||
Args: []ssa.Value{value},
|
Source: ssa.Source(tokens),
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/expression"
|
"git.urbach.dev/cli/q/src/expression"
|
||||||
"git.urbach.dev/cli/q/src/ssa"
|
"git.urbach.dev/cli/q/src/ssa"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Evaluate converts an expression to an SSA value.
|
// Evaluate converts an expression to an SSA value.
|
||||||
|
@ -26,8 +27,8 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Dependencies.Add(function)
|
f.Dependencies.Add(function)
|
||||||
v := f.AppendFunction(function.UniqueName)
|
v := f.AppendFunction(function.UniqueName, function.Type)
|
||||||
v.Source = expr.Token
|
v.Source = ssa.Source(expr.Source)
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,14 +42,14 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
v := f.AppendInt(number)
|
v := f.AppendInt(number)
|
||||||
v.Source = expr.Token
|
v.Source = ssa.Source(expr.Source)
|
||||||
return v, nil
|
return v, nil
|
||||||
|
|
||||||
case token.String:
|
case token.String:
|
||||||
data := expr.Token.Bytes(f.File.Bytes)
|
data := expr.Token.Bytes(f.File.Bytes)
|
||||||
data = Unescape(data)
|
data = Unescape(data)
|
||||||
v := f.AppendBytes(data)
|
v := f.AppendBytes(data)
|
||||||
v.Source = expr.Token
|
v.Source = ssa.Source(expr.Source)
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +66,13 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
|
|
||||||
if funcName == "len" {
|
if funcName == "len" {
|
||||||
identifier := children[1].String(f.File.Bytes)
|
identifier := children[1].String(f.File.Bytes)
|
||||||
return f.Identifiers[identifier+".length"], nil
|
length, exists := f.Identifiers[identifier+".len"]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return nil, errors.New(&UnknownIdentifier{Name: identifier + ".len"}, f.File, expr.Token.Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
return length, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if funcName == "syscall" {
|
if funcName == "syscall" {
|
||||||
|
@ -87,19 +94,37 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSyscall {
|
if isSyscall {
|
||||||
v := f.Append(&ssa.Syscall{
|
syscall := &ssa.Syscall{
|
||||||
Arguments: ssa.Arguments{Args: args},
|
Arguments: args,
|
||||||
HasToken: ssa.HasToken{Source: expr.Token},
|
Source: ssa.Source(expr.Source),
|
||||||
})
|
}
|
||||||
|
|
||||||
return v, nil
|
return f.Append(syscall), nil
|
||||||
} else {
|
} else {
|
||||||
v := f.Append(&ssa.Call{
|
name := args[0].(*ssa.Function).UniqueName
|
||||||
Arguments: ssa.Arguments{Args: args},
|
fn := f.All.Functions[name]
|
||||||
HasToken: ssa.HasToken{Source: expr.Token},
|
parameters := args[1:]
|
||||||
})
|
|
||||||
|
|
||||||
return v, nil
|
if len(parameters) != len(fn.Input) {
|
||||||
|
return nil, errors.New(&ParameterCountMismatch{Function: name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, expr.Source[0].Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, param := range parameters {
|
||||||
|
if !types.Is(param.Type(), fn.Input[i].Typ) {
|
||||||
|
return nil, errors.New(&TypeMismatch{
|
||||||
|
Encountered: param.Type().Name(),
|
||||||
|
Expected: fn.Input[i].Typ.Name(),
|
||||||
|
ParameterName: fn.Input[i].Name,
|
||||||
|
}, f.File, param.Start())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
call := &ssa.Call{
|
||||||
|
Arguments: args,
|
||||||
|
Source: ssa.Source(expr.Source),
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Append(call), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
case token.Dot:
|
case token.Dot:
|
||||||
|
@ -113,8 +138,8 @@ func (f *Function) Evaluate(expr *expression.Expression) (ssa.Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Dependencies.Add(function)
|
f.Dependencies.Add(function)
|
||||||
v := f.AppendFunction(function.UniqueName)
|
v := f.AppendFunction(function.UniqueName, function.Type)
|
||||||
v.Source = expr.Children[1].Token
|
v.Source = ssa.Source(expr.Source)
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/set"
|
"git.urbach.dev/cli/q/src/set"
|
||||||
"git.urbach.dev/cli/q/src/ssa"
|
"git.urbach.dev/cli/q/src/ssa"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Function is the smallest unit of code.
|
// Function is the smallest unit of code.
|
||||||
|
@ -17,14 +18,15 @@ type Function struct {
|
||||||
Name string
|
Name string
|
||||||
UniqueName string
|
UniqueName string
|
||||||
File *fs.File
|
File *fs.File
|
||||||
Input []*Parameter
|
Input []*ssa.Parameter
|
||||||
Output []*Parameter
|
Output []*ssa.Parameter
|
||||||
Body token.List
|
Body token.List
|
||||||
Identifiers map[string]ssa.Value
|
Identifiers map[string]ssa.Value
|
||||||
All *Environment
|
All *Environment
|
||||||
Dependencies set.Ordered[*Function]
|
Dependencies set.Ordered[*Function]
|
||||||
Assembler asm.Assembler
|
Assembler asm.Assembler
|
||||||
CPU *cpu.CPU
|
CPU *cpu.CPU
|
||||||
|
Type *types.Function
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,4 @@ func TestFunction(t *testing.T) {
|
||||||
assert.False(t, main.IsExtern())
|
assert.False(t, main.IsExtern())
|
||||||
assert.Equal(t, main.UniqueName, "main.main")
|
assert.Equal(t, main.UniqueName, "main.main")
|
||||||
assert.Equal(t, main.String(), main.UniqueName)
|
assert.Equal(t, main.String(), main.UniqueName)
|
||||||
|
|
||||||
write, exists := env.Functions["io.write"]
|
|
||||||
assert.True(t, exists)
|
|
||||||
write.Output[0].Type()
|
|
||||||
}
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.urbach.dev/cli/q/src/token"
|
|
||||||
"git.urbach.dev/cli/q/src/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parameter is an input or output parameter in a function.
|
|
||||||
type Parameter struct {
|
|
||||||
Name string
|
|
||||||
TypeTokens token.List
|
|
||||||
typ types.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the data type of the parameter.
|
|
||||||
func (p *Parameter) Type() types.Type {
|
|
||||||
return p.typ
|
|
||||||
}
|
|
|
@ -12,6 +12,43 @@ var (
|
||||||
InvalidRune = errors.String("Invalid rune")
|
InvalidRune = errors.String("Invalid rune")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ParameterCountMismatch error is created when the number of provided parameters doesn't match the function signature.
|
||||||
|
type ParameterCountMismatch struct {
|
||||||
|
Function string
|
||||||
|
Count int
|
||||||
|
ExpectedCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ParameterCountMismatch) Error() string {
|
||||||
|
if err.Count > err.ExpectedCount {
|
||||||
|
return fmt.Sprintf("Too many parameters in '%s' function call", err.Function)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Not enough parameters in '%s' function call", err.Function)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeMismatch represents an error where a type requirement was not met.
|
||||||
|
type TypeMismatch struct {
|
||||||
|
Encountered string
|
||||||
|
Expected string
|
||||||
|
ParameterName string
|
||||||
|
IsReturn bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *TypeMismatch) Error() string {
|
||||||
|
subject := "type"
|
||||||
|
|
||||||
|
if err.IsReturn {
|
||||||
|
subject = "return type"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err.ParameterName != "" {
|
||||||
|
return fmt.Sprintf("Expected parameter '%s' of %s '%s' (encountered '%s')", err.ParameterName, subject, err.Expected, err.Encountered)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("Expected %s '%s' instead of '%s'", subject, err.Expected, err.Encountered)
|
||||||
|
}
|
||||||
|
|
||||||
// UnknownIdentifier represents unknown identifiers.
|
// UnknownIdentifier represents unknown identifiers.
|
||||||
type UnknownIdentifier struct {
|
type UnknownIdentifier struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
|
@ -11,6 +11,7 @@ type Expression struct {
|
||||||
Parent *Expression
|
Parent *Expression
|
||||||
Children []*Expression
|
Children []*Expression
|
||||||
Token token.Token
|
Token token.Token
|
||||||
|
Source token.List
|
||||||
precedence int8
|
precedence int8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse generates an expression tree from tokens.
|
// Parse generates an expression tree from tokens.
|
||||||
func Parse(tokens []token.Token) *Expression {
|
func Parse(tokens token.List) *Expression {
|
||||||
var (
|
var (
|
||||||
cursor *Expression
|
cursor *Expression
|
||||||
root *Expression
|
root *Expression
|
||||||
groupLevel = 0
|
groupLevel = 0
|
||||||
groupPosition = 0
|
groupPosition = 0
|
||||||
|
cursorStart = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, t := range tokens {
|
for i, t := range tokens {
|
||||||
|
@ -38,6 +39,7 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
parameters := NewList(tokens[groupPosition:i])
|
parameters := NewList(tokens[groupPosition:i])
|
||||||
node := New()
|
node := New()
|
||||||
node.Token.Position = tokens[groupPosition].Position
|
node.Token.Position = tokens[groupPosition].Position
|
||||||
|
node.Source = tokens[groupPosition:i]
|
||||||
|
|
||||||
switch t.Kind {
|
switch t.Kind {
|
||||||
case token.GroupEnd:
|
case token.GroupEnd:
|
||||||
|
@ -72,6 +74,7 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group.Source = tokens[groupPosition:i]
|
||||||
group.precedence = math.MaxInt8
|
group.precedence = math.MaxInt8
|
||||||
|
|
||||||
if cursor == nil {
|
if cursor == nil {
|
||||||
|
@ -79,6 +82,7 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
cursor = New()
|
cursor = New()
|
||||||
cursor.Token.Position = tokens[groupPosition].Position
|
cursor.Token.Position = tokens[groupPosition].Position
|
||||||
cursor.Token.Kind = token.Array
|
cursor.Token.Kind = token.Array
|
||||||
|
cursor.Source = tokens[groupPosition:i]
|
||||||
cursor.precedence = precedence(token.Array)
|
cursor.precedence = precedence(token.Array)
|
||||||
cursor.AddChild(group)
|
cursor.AddChild(group)
|
||||||
root = cursor
|
root = cursor
|
||||||
|
@ -88,6 +92,7 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cursor.AddChild(group)
|
cursor.AddChild(group)
|
||||||
|
cursor.Source = tokens[cursorStart : i+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
@ -100,9 +105,13 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
if t.Kind == token.Identifier || t.Kind == token.Number || t.Kind == token.String || t.Kind == token.Rune {
|
if t.Kind == token.Identifier || t.Kind == token.Number || t.Kind == token.String || t.Kind == token.Rune {
|
||||||
if cursor != nil {
|
if cursor != nil {
|
||||||
node := NewLeaf(t)
|
node := NewLeaf(t)
|
||||||
|
node.Source = tokens[i : i+1]
|
||||||
|
cursor.Source = tokens[cursorStart : i+1]
|
||||||
cursor.AddChild(node)
|
cursor.AddChild(node)
|
||||||
} else {
|
} else {
|
||||||
cursor = NewLeaf(t)
|
cursor = NewLeaf(t)
|
||||||
|
cursorStart = i
|
||||||
|
cursor.Source = tokens[i : i+1]
|
||||||
root = cursor
|
root = cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,12 +124,15 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
|
|
||||||
if cursor == nil {
|
if cursor == nil {
|
||||||
cursor = NewLeaf(t)
|
cursor = NewLeaf(t)
|
||||||
|
cursorStart = i
|
||||||
|
cursor.Source = tokens[i : i+1]
|
||||||
cursor.precedence = precedence(t.Kind)
|
cursor.precedence = precedence(t.Kind)
|
||||||
root = cursor
|
root = cursor
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
node := NewLeaf(t)
|
node := NewLeaf(t)
|
||||||
|
node.Source = tokens[i : i+1]
|
||||||
node.precedence = precedence(t.Kind)
|
node.precedence = precedence(t.Kind)
|
||||||
|
|
||||||
if cursor.Token.IsOperator() {
|
if cursor.Token.IsOperator() {
|
||||||
|
@ -131,6 +143,7 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
if len(cursor.Children) == numOperands(cursor.Token.Kind) {
|
if len(cursor.Children) == numOperands(cursor.Token.Kind) {
|
||||||
cursor.LastChild().InsertAbove(node)
|
cursor.LastChild().InsertAbove(node)
|
||||||
} else {
|
} else {
|
||||||
|
cursor.Source = tokens[cursorStart : i+1]
|
||||||
cursor.AddChild(node)
|
cursor.AddChild(node)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -169,5 +182,9 @@ func Parse(tokens []token.Token) *Expression {
|
||||||
cursor = node
|
cursor = node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if root != nil {
|
||||||
|
root.Source = tokens
|
||||||
|
}
|
||||||
|
|
||||||
return root
|
return root
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"git.urbach.dev/cli/q/src/core"
|
"git.urbach.dev/cli/q/src/core"
|
||||||
"git.urbach.dev/cli/q/src/errors"
|
"git.urbach.dev/cli/q/src/errors"
|
||||||
"git.urbach.dev/cli/q/src/fs"
|
"git.urbach.dev/cli/q/src/fs"
|
||||||
|
"git.urbach.dev/cli/q/src/ssa"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -94,9 +95,9 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
||||||
return nil, i, errors.New(MissingType, file, param[0].End())
|
return nil, i, errors.New(MissingType, file, param[0].End())
|
||||||
}
|
}
|
||||||
|
|
||||||
function.Input = append(function.Input, &core.Parameter{
|
function.Input = append(function.Input, &ssa.Parameter{
|
||||||
Name: param[0].String(file.Bytes),
|
Name: param[0].String(file.Bytes),
|
||||||
TypeTokens: param[1:],
|
Source: ssa.Source(param),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,18 +128,19 @@ func scanSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(param) == 1 {
|
if len(param) == 1 {
|
||||||
function.Output = append(function.Output, &core.Parameter{
|
function.Output = append(function.Output, &ssa.Parameter{
|
||||||
Name: "",
|
Name: "",
|
||||||
TypeTokens: param,
|
Source: ssa.Source(param),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
function.Output = append(function.Output, &core.Parameter{
|
function.Output = append(function.Output, &ssa.Parameter{
|
||||||
Name: param[0].String(file.Bytes),
|
Name: param[0].String(file.Bytes),
|
||||||
TypeTokens: param[1:],
|
Source: ssa.Source(param),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
errorPos = param[len(param)-1].End() + 1
|
errorPos = param[len(param)-1].End() + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return function, i, nil
|
return function, i, nil
|
||||||
}
|
}
|
|
@ -1,20 +1,18 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
type Arguments struct {
|
type Arguments []Value
|
||||||
Args []Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Arguments) Dependencies() []Value {
|
func (v Arguments) Dependencies() []Value {
|
||||||
return v.Args
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a Arguments) Equals(b Arguments) bool {
|
func (a Arguments) Equals(b Arguments) bool {
|
||||||
if len(a.Args) != len(b.Args) {
|
if len(a) != len(b) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range a.Args {
|
for i := range a {
|
||||||
if !a.Args[i].Equals(b.Args[i]) {
|
if !a[i].Equals(b[i]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/expression"
|
"git.urbach.dev/cli/q/src/expression"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BinaryOperation struct {
|
type BinaryOperation struct {
|
||||||
|
@ -12,7 +13,7 @@ type BinaryOperation struct {
|
||||||
Right Value
|
Right Value
|
||||||
Op token.Kind
|
Op token.Kind
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *BinaryOperation) Dependencies() []Value {
|
func (v *BinaryOperation) Dependencies() []Value {
|
||||||
|
@ -26,10 +27,6 @@ func (a *BinaryOperation) Equals(v Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.Source.Kind != b.Source.Kind {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !a.Left.Equals(b.Left) {
|
if !a.Left.Equals(b.Left) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -48,3 +45,7 @@ func (v *BinaryOperation) IsConst() bool {
|
||||||
func (v *BinaryOperation) String() string {
|
func (v *BinaryOperation) String() string {
|
||||||
return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right)
|
return fmt.Sprintf("%s %s %s", v.Left, expression.Operators[v.Op].Symbol, v.Right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *BinaryOperation) Type() types.Type {
|
||||||
|
return v.Left.Type()
|
||||||
|
}
|
|
@ -1,11 +1,16 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "bytes"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Bytes struct {
|
type Bytes struct {
|
||||||
Bytes []byte
|
Bytes []byte
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Bytes) Dependencies() []Value {
|
func (v *Bytes) Dependencies() []Value {
|
||||||
|
@ -27,5 +32,9 @@ func (v *Bytes) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Bytes) String() string {
|
func (v *Bytes) String() string {
|
||||||
return string(v.Bytes)
|
return strconv.Quote(string(v.Bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Bytes) Type() types.Type {
|
||||||
|
return types.String
|
||||||
}
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Call struct {
|
type Call struct {
|
||||||
Arguments
|
Arguments
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Call) Equals(v Value) bool {
|
func (a *Call) Equals(v Value) bool {
|
||||||
|
@ -23,5 +27,15 @@ func (v *Call) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Call) String() string {
|
func (v *Call) String() string {
|
||||||
return fmt.Sprintf("call%v", v.Args)
|
return fmt.Sprintf("%s(%v)", v.Arguments[0], v.Arguments[1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Call) Type() types.Type {
|
||||||
|
typ := v.Arguments[0].(*Function).Typ
|
||||||
|
|
||||||
|
if len(typ.Output) == 0 {
|
||||||
|
return types.Void
|
||||||
|
}
|
||||||
|
|
||||||
|
return typ.Output[0]
|
||||||
}
|
}
|
|
@ -1,9 +1,12 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/types"
|
||||||
|
|
||||||
type Function struct {
|
type Function struct {
|
||||||
UniqueName string
|
UniqueName string
|
||||||
|
Typ *types.Function
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Function) Dependencies() []Value {
|
func (v *Function) Dependencies() []Value {
|
||||||
|
@ -27,3 +30,7 @@ func (v *Function) IsConst() bool {
|
||||||
func (v *Function) String() string {
|
func (v *Function) String() string {
|
||||||
return v.UniqueName
|
return v.UniqueName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Function) Type() types.Type {
|
||||||
|
return v.Typ
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
package ssa
|
|
||||||
|
|
||||||
import "git.urbach.dev/cli/q/src/token"
|
|
||||||
|
|
||||||
type HasToken struct {
|
|
||||||
Source token.Token
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *HasToken) Token() token.Token {
|
|
||||||
return v.Source
|
|
||||||
}
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/types"
|
||||||
|
|
||||||
// IR is a list of basic blocks.
|
// IR is a list of basic blocks.
|
||||||
type IR struct {
|
type IR struct {
|
||||||
Blocks []*Block
|
Blocks []*Block
|
||||||
|
@ -39,16 +41,9 @@ func (f *IR) AppendInt(x int) *Int {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendRegister adds a new register value to the last block.
|
|
||||||
func (f *IR) AppendRegister(index int) *Parameter {
|
|
||||||
v := &Parameter{Index: uint8(index)}
|
|
||||||
f.Append(v)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendFunction adds a new function value to the last block.
|
// AppendFunction adds a new function value to the last block.
|
||||||
func (f *IR) AppendFunction(name string) *Function {
|
func (f *IR) AppendFunction(name string, typ *types.Function) *Function {
|
||||||
v := &Function{UniqueName: name}
|
v := &Function{UniqueName: name, Typ: typ}
|
||||||
f.Append(v)
|
f.Append(v)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,14 @@ package ssa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Int struct {
|
type Int struct {
|
||||||
Int int
|
Int int
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Int) Dependencies() []Value {
|
func (v *Int) Dependencies() []Value {
|
||||||
|
@ -31,3 +33,7 @@ func (v *Int) IsConst() bool {
|
||||||
func (v *Int) String() string {
|
func (v *Int) String() string {
|
||||||
return fmt.Sprintf("%d", v.Int)
|
return fmt.Sprintf("%d", v.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Int) Type() types.Type {
|
||||||
|
return types.AnyInt
|
||||||
|
}
|
|
@ -1,11 +1,17 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Parameter struct {
|
type Parameter struct {
|
||||||
Index uint8
|
Index uint8
|
||||||
|
Name string
|
||||||
|
Typ types.Type
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Parameter) Dependencies() []Value {
|
func (v *Parameter) Dependencies() []Value {
|
||||||
|
@ -27,5 +33,9 @@ func (v *Parameter) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Parameter) String() string {
|
func (v *Parameter) String() string {
|
||||||
return fmt.Sprintf("arg[%d]", v.Index)
|
return fmt.Sprintf("in[%d]", v.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Parameter) Type() types.Type {
|
||||||
|
return v.Typ
|
||||||
}
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Return struct {
|
type Return struct {
|
||||||
Arguments
|
Arguments
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Return) AddUse(user Value) { panic("return is not a value") }
|
func (a *Return) AddUse(user Value) { panic("return is not a value") }
|
||||||
|
@ -17,12 +21,12 @@ func (a *Return) Equals(v Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.Args) != len(b.Args) {
|
if len(a.Arguments) != len(b.Arguments) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range a.Args {
|
for i := range a.Arguments {
|
||||||
if !a.Args[i].Equals(b.Args[i]) {
|
if !a.Arguments[i].Equals(b.Arguments[i]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,5 +39,9 @@ func (v *Return) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Return) String() string {
|
func (v *Return) String() string {
|
||||||
return fmt.Sprintf("return %v", v.Args)
|
return fmt.Sprintf("return %v", v.Arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Return) Type() types.Type {
|
||||||
|
return types.Void
|
||||||
}
|
}
|
13
src/ssa/Source.go
Normal file
13
src/ssa/Source.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package ssa
|
||||||
|
|
||||||
|
import "git.urbach.dev/cli/q/src/token"
|
||||||
|
|
||||||
|
type Source token.List
|
||||||
|
|
||||||
|
func (v Source) Start() token.Position {
|
||||||
|
return v[0].Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Source) End() token.Position {
|
||||||
|
return v[len(v)-1].End()
|
||||||
|
}
|
|
@ -1,11 +1,15 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Syscall struct {
|
type Syscall struct {
|
||||||
Arguments
|
Arguments
|
||||||
Liveness
|
Liveness
|
||||||
HasToken
|
Source
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Syscall) Equals(v Value) bool {
|
func (a *Syscall) Equals(v Value) bool {
|
||||||
|
@ -23,5 +27,9 @@ func (v *Syscall) IsConst() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Syscall) String() string {
|
func (v *Syscall) String() string {
|
||||||
return fmt.Sprintf("syscall%v", v.Args)
|
return fmt.Sprintf("syscall(%v)", v.Arguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Syscall) Type() types.Type {
|
||||||
|
return types.Any
|
||||||
}
|
}
|
|
@ -1,13 +1,18 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "git.urbach.dev/cli/q/src/token"
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
"git.urbach.dev/cli/q/src/types"
|
||||||
|
)
|
||||||
|
|
||||||
type Value interface {
|
type Value interface {
|
||||||
AddUse(Value)
|
AddUse(Value)
|
||||||
Alive() int
|
Alive() int
|
||||||
Dependencies() []Value
|
Dependencies() []Value
|
||||||
|
End() token.Position
|
||||||
Equals(Value) bool
|
Equals(Value) bool
|
||||||
IsConst() bool
|
IsConst() bool
|
||||||
String() string
|
String() string
|
||||||
Token() token.Token
|
Start() token.Position
|
||||||
|
Type() types.Type
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@ var (
|
||||||
UInt32 = &Base{name: "uint32", size: 4}
|
UInt32 = &Base{name: "uint32", size: 4}
|
||||||
UInt16 = &Base{name: "uint16", size: 2}
|
UInt16 = &Base{name: "uint16", size: 2}
|
||||||
UInt8 = &Base{name: "uint8", size: 1}
|
UInt8 = &Base{name: "uint8", size: 1}
|
||||||
|
Void = &Base{name: "void", size: 0}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
47
src/types/Function.go
Normal file
47
src/types/Function.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// Function transforms inputs to new outputs.
|
||||||
|
type Function struct {
|
||||||
|
Input []Type
|
||||||
|
Output []Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the type name.
|
||||||
|
func (f *Function) Name() string {
|
||||||
|
builder := strings.Builder{}
|
||||||
|
builder.WriteString("(")
|
||||||
|
|
||||||
|
for i, input := range f.Input {
|
||||||
|
builder.WriteString(input.Name())
|
||||||
|
|
||||||
|
if i != len(f.Input)-1 {
|
||||||
|
builder.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(")")
|
||||||
|
|
||||||
|
if len(f.Output) == 0 {
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(" -> (")
|
||||||
|
|
||||||
|
for i, output := range f.Output {
|
||||||
|
builder.WriteString(output.Name())
|
||||||
|
|
||||||
|
if i != len(f.Output)-1 {
|
||||||
|
builder.WriteString(",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.WriteString(")")
|
||||||
|
return builder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the total size in bytes.
|
||||||
|
func (f *Function) Size() int {
|
||||||
|
return 8
|
||||||
|
}
|
71
src/types/Parse.go
Normal file
71
src/types/Parse.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parse returns the type with the given tokens or `nil` if it doesn't exist.
|
||||||
|
func Parse[T ~[]token.Token](tokens T, source []byte) Type {
|
||||||
|
if tokens[0].Kind == token.Mul {
|
||||||
|
to := tokens[1:]
|
||||||
|
typ := Parse(to, source)
|
||||||
|
|
||||||
|
if typ == Any {
|
||||||
|
return AnyPointer
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Pointer{To: typ}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tokens) >= 2 && tokens[0].Kind == token.ArrayStart && tokens[1].Kind == token.ArrayEnd {
|
||||||
|
to := tokens[2:]
|
||||||
|
typ := Parse(to, source)
|
||||||
|
|
||||||
|
if typ == Any {
|
||||||
|
return AnyArray
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Array{Of: typ}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tokens[0].Kind != token.Identifier {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tokens[0].String(source) {
|
||||||
|
case "int":
|
||||||
|
return Int
|
||||||
|
case "int64":
|
||||||
|
return Int64
|
||||||
|
case "int32":
|
||||||
|
return Int32
|
||||||
|
case "int16":
|
||||||
|
return Int16
|
||||||
|
case "int8":
|
||||||
|
return Int8
|
||||||
|
case "uint":
|
||||||
|
return UInt
|
||||||
|
case "uint64":
|
||||||
|
return UInt64
|
||||||
|
case "uint32":
|
||||||
|
return UInt32
|
||||||
|
case "uint16":
|
||||||
|
return UInt16
|
||||||
|
case "uint8":
|
||||||
|
return UInt8
|
||||||
|
case "byte":
|
||||||
|
return Byte
|
||||||
|
case "bool":
|
||||||
|
return Bool
|
||||||
|
case "float":
|
||||||
|
return Float
|
||||||
|
case "float64":
|
||||||
|
return Float64
|
||||||
|
case "float32":
|
||||||
|
return Float32
|
||||||
|
case "any":
|
||||||
|
return Any
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue