Added types
This commit is contained in:
parent
67a37cdb26
commit
6e848774ed
@ -25,7 +25,7 @@ func (f *Function) Compare(comparison *expression.Expression) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ast.IsFunctionCall(left) && right.IsLeaf() {
|
if ast.IsFunctionCall(left) && right.IsLeaf() {
|
||||||
err := f.CompileCall(left)
|
_, err := f.CompileCall(left)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -35,7 +35,7 @@ func (f *Function) Compare(comparison *expression.Expression) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmp := f.NewRegister()
|
tmp := f.NewRegister()
|
||||||
err := f.ExpressionToRegister(left, tmp)
|
_, err := f.ExpressionToRegister(left, tmp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -17,7 +17,8 @@ func (f *Function) CompileASTNode(node ast.Node) error {
|
|||||||
|
|
||||||
case *ast.Call:
|
case *ast.Call:
|
||||||
f.Fold(node.Expression)
|
f.Fold(node.Expression)
|
||||||
return f.CompileCall(node.Expression)
|
_, err := f.CompileCall(node.Expression)
|
||||||
|
return err
|
||||||
|
|
||||||
case *ast.Define:
|
case *ast.Define:
|
||||||
f.Fold(node.Expression)
|
f.Fold(node.Expression)
|
||||||
|
@ -33,5 +33,6 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error {
|
|||||||
Length: byte(1),
|
Length: byte(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.ExpressionToMemory(right, memory)
|
_, err = f.ExpressionToMemory(right, memory)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func (f *Function) CompileAssignDivision(node *ast.Assign) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dividend := right.Children[0]
|
dividend := right.Children[0]
|
||||||
dividendRegister, err := f.Evaluate(dividend)
|
_, dividendRegister, err := f.Evaluate(dividend)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -12,12 +12,14 @@ import (
|
|||||||
// All call registers must hold the correct parameter values before the function invocation.
|
// All call registers must hold the correct parameter values before the function invocation.
|
||||||
// Registers that are in use must be saved if they are modified by the function.
|
// Registers that are in use must be saved if they are modified by the function.
|
||||||
// After the function call, they must be restored in reverse order.
|
// After the function call, they must be restored in reverse order.
|
||||||
func (f *Function) CompileCall(root *expression.Expression) error {
|
func (f *Function) CompileCall(root *expression.Expression) (*Function, error) {
|
||||||
var (
|
var (
|
||||||
pkg = f.Package
|
pkg = f.Package
|
||||||
nameRoot = root.Children[0]
|
nameRoot = root.Children[0]
|
||||||
|
fn *Function
|
||||||
name string
|
name string
|
||||||
fullName string
|
fullName string
|
||||||
|
exists bool
|
||||||
)
|
)
|
||||||
|
|
||||||
if nameRoot.IsLeaf() {
|
if nameRoot.IsLeaf() {
|
||||||
@ -32,13 +34,13 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
|||||||
if !isSyscall {
|
if !isSyscall {
|
||||||
if pkg != f.File.Package {
|
if pkg != f.File.Package {
|
||||||
if f.File.Imports == nil {
|
if f.File.Imports == nil {
|
||||||
return errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameRoot.Token.Position)
|
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameRoot.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
imp, exists := f.File.Imports[pkg]
|
imp, exists := f.File.Imports[pkg]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameRoot.Token.Position)
|
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, nameRoot.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
imp.Used = true
|
imp.Used = true
|
||||||
@ -49,10 +51,10 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
|||||||
tmp.WriteString(".")
|
tmp.WriteString(".")
|
||||||
tmp.WriteString(name)
|
tmp.WriteString(name)
|
||||||
fullName = tmp.String()
|
fullName = tmp.String()
|
||||||
_, exists := f.Functions[fullName]
|
fn, exists = f.Functions[fullName]
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
return errors.New(&errors.UnknownFunction{Name: name}, f.File, nameRoot.Token.Position)
|
return nil, errors.New(&errors.UnknownFunction{Name: name}, f.File, nameRoot.Token.Position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
|||||||
err := f.ExpressionsToRegisters(parameters, registers)
|
err := f.ExpressionsToRegisters(parameters, registers)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Save all return value registers of the function
|
// TODO: Save all return value registers of the function
|
||||||
@ -104,5 +106,5 @@ func (f *Function) CompileCall(root *expression.Expression) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return fn, nil
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/ast"
|
"git.akyoto.dev/cli/q/src/build/ast"
|
||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompileDefinition compiles a variable definition.
|
// CompileDefinition compiles a variable definition.
|
||||||
@ -19,9 +20,20 @@ func (f *Function) CompileDefinition(node *ast.Define) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f.ExpressionToRegister(right, variable.Register)
|
typ, err := f.ExpressionToRegister(right, variable.Register)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
variable.Type = typ
|
||||||
|
|
||||||
|
if variable.Type == types.Invalid {
|
||||||
|
return errors.New(errors.UnknownType, f.File, node.Expression.Token.End())
|
||||||
|
}
|
||||||
|
|
||||||
f.AddVariable(variable)
|
f.AddVariable(variable)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ast.IsFunctionCall(right) {
|
if !ast.IsFunctionCall(right) {
|
||||||
@ -29,7 +41,7 @@ func (f *Function) CompileDefinition(node *ast.Define) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
err := f.CompileCall(right)
|
_, err := f.CompileCall(right)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -4,21 +4,22 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Evaluate evaluates an expression and returns a register that contains the value of the expression.
|
// Evaluate evaluates an expression and returns a register that contains the value of the expression.
|
||||||
func (f *Function) Evaluate(expr *expression.Expression) (cpu.Register, error) {
|
func (f *Function) Evaluate(expr *expression.Expression) (types.Type, cpu.Register, error) {
|
||||||
if expr.Token.Kind == token.Identifier {
|
if expr.Token.Kind == token.Identifier {
|
||||||
name := expr.Token.Text(f.File.Bytes)
|
name := expr.Token.Text(f.File.Bytes)
|
||||||
variable := f.VariableByName(name)
|
variable := f.VariableByName(name)
|
||||||
|
|
||||||
if variable.Alive == 1 {
|
if variable.Alive == 1 {
|
||||||
f.UseVariable(variable)
|
f.UseVariable(variable)
|
||||||
return variable.Register, nil
|
return variable.Type, variable.Register, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := f.NewRegister()
|
tmp := f.NewRegister()
|
||||||
err := f.ExpressionToRegister(expr, tmp)
|
typ, err := f.ExpressionToRegister(expr, tmp)
|
||||||
return tmp, err
|
return typ, tmp, err
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ast.IsFunctionCall(value) {
|
if ast.IsFunctionCall(value) {
|
||||||
err := f.CompileCall(value)
|
_, err := f.CompileCall(value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -26,7 +26,7 @@ func (f *Function) Execute(operation token.Token, register cpu.Register, value *
|
|||||||
tmp := f.NewRegister()
|
tmp := f.NewRegister()
|
||||||
defer f.FreeRegister(tmp)
|
defer f.FreeRegister(tmp)
|
||||||
|
|
||||||
err := f.ExpressionToRegister(value, tmp)
|
_, err := f.ExpressionToRegister(value, tmp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,7 +31,8 @@ func (f *Function) ExecuteLeaf(operation token.Token, register cpu.Register, ope
|
|||||||
|
|
||||||
case token.String:
|
case token.String:
|
||||||
if operation.Kind == token.Assign {
|
if operation.Kind == token.Assign {
|
||||||
return f.TokenToRegister(operand, register)
|
_, err := f.TokenToRegister(operand, register)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,30 +5,31 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
"git.akyoto.dev/cli/q/src/build/sizeof"
|
"git.akyoto.dev/cli/q/src/build/sizeof"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExpressionToMemory puts the result of an expression into the specified memory address.
|
// ExpressionToMemory puts the result of an expression into the specified memory address.
|
||||||
func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Memory) error {
|
func (f *Function) ExpressionToMemory(node *expression.Expression, memory asm.Memory) (types.Type, error) {
|
||||||
if node.IsLeaf() && node.Token.IsNumeric() {
|
if node.IsLeaf() && node.Token.IsNumeric() {
|
||||||
number, err := f.Number(node.Token)
|
number, err := f.Number(node.Token)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return types.Invalid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
size := byte(sizeof.Signed(int64(number)))
|
size := byte(sizeof.Signed(int64(number)))
|
||||||
|
|
||||||
if size != memory.Length {
|
if size != memory.Length {
|
||||||
return errors.New(&errors.NumberExceedsBounds{Number: number, ExpectedSize: memory.Length, Size: size}, f.File, node.Token.Position)
|
return types.Invalid, errors.New(&errors.NumberExceedsBounds{Number: number, ExpectedSize: memory.Length, Size: size}, f.File, node.Token.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.MemoryNumber(asm.STORE, memory, number)
|
f.MemoryNumber(asm.STORE, memory, number)
|
||||||
return nil
|
return types.Int, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := f.NewRegister()
|
tmp := f.NewRegister()
|
||||||
defer f.FreeRegister(tmp)
|
defer f.FreeRegister(tmp)
|
||||||
err := f.ExpressionToRegister(node, tmp)
|
typ, err := f.ExpressionToRegister(node, tmp)
|
||||||
f.MemoryRegister(asm.STORE, memory, tmp)
|
f.MemoryRegister(asm.STORE, memory, tmp)
|
||||||
return err
|
return typ, err
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,16 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
"git.akyoto.dev/cli/q/src/build/expression"
|
"git.akyoto.dev/cli/q/src/build/expression"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExpressionToRegister puts the result of an expression into the specified register.
|
// ExpressionToRegister puts the result of an expression into the specified register.
|
||||||
func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) error {
|
func (f *Function) ExpressionToRegister(node *expression.Expression, register cpu.Register) (types.Type, error) {
|
||||||
f.SaveRegister(register)
|
f.SaveRegister(register)
|
||||||
|
|
||||||
if node.IsFolded {
|
if node.IsFolded {
|
||||||
f.RegisterNumber(asm.MOVE, register, node.Value)
|
f.RegisterNumber(asm.MOVE, register, node.Value)
|
||||||
return nil
|
return types.Int, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.IsLeaf() {
|
if node.IsLeaf() {
|
||||||
@ -23,34 +24,38 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ast.IsFunctionCall(node) {
|
if ast.IsFunctionCall(node) {
|
||||||
err := f.CompileCall(node)
|
fn, err := f.CompileCall(node)
|
||||||
|
|
||||||
if register != f.CPU.Output[0] {
|
if register != f.CPU.Output[0] {
|
||||||
f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0])
|
f.RegisterRegister(asm.MOVE, register, f.CPU.Output[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
if fn == nil || len(fn.ReturnTypes) == 0 {
|
||||||
|
return types.Invalid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn.ReturnTypes[0], err
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.Token.Kind == token.Array {
|
if node.Token.Kind == token.Array {
|
||||||
array := f.VariableByName(node.Children[0].Token.Text(f.File.Bytes))
|
array := f.VariableByName(node.Children[0].Token.Text(f.File.Bytes))
|
||||||
offset, err := f.Number(node.Children[1].Token)
|
offset, err := f.Number(node.Children[1].Token)
|
||||||
f.MemoryRegister(asm.LOAD, asm.Memory{Base: array.Register, Offset: byte(offset), Length: 1}, register)
|
f.MemoryRegister(asm.LOAD, asm.Memory{Base: array.Register, Offset: byte(offset), Length: 1}, register)
|
||||||
return err
|
return types.Int, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(node.Children) == 1 {
|
if len(node.Children) == 1 {
|
||||||
if !node.Token.IsUnaryOperator() {
|
if !node.Token.IsUnaryOperator() {
|
||||||
return errors.New(errors.MissingOperand, f.File, node.Token.End())
|
return types.Invalid, errors.New(errors.MissingOperand, f.File, node.Token.End())
|
||||||
}
|
}
|
||||||
|
|
||||||
err := f.ExpressionToRegister(node.Children[0], register)
|
typ, err := f.ExpressionToRegister(node.Children[0], register)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return typ, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return f.ExecuteRegister(node.Token, register)
|
return typ, f.ExecuteRegister(node.Token, register)
|
||||||
}
|
}
|
||||||
|
|
||||||
left := node.Children[0]
|
left := node.Children[0]
|
||||||
@ -61,10 +66,10 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
|||||||
register = f.NewRegister()
|
register = f.NewRegister()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := f.ExpressionToRegister(left, register)
|
typ, err := f.ExpressionToRegister(left, register)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return types.Invalid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f.Execute(node.Token, register, right)
|
err = f.Execute(node.Token, register, right)
|
||||||
@ -74,5 +79,5 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp
|
|||||||
f.FreeRegister(register)
|
f.FreeRegister(register)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return typ, err
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
// ExpressionsToRegisters moves multiple expressions into the specified registers.
|
||||||
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
func (f *Function) ExpressionsToRegisters(expressions []*expression.Expression, registers []cpu.Register) error {
|
||||||
for i := len(expressions) - 1; i >= 0; i-- {
|
for i := len(expressions) - 1; i >= 0; i-- {
|
||||||
err := f.ExpressionToRegister(expressions[i], registers[i])
|
_, err := f.ExpressionToRegister(expressions[i], registers[i])
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -3,21 +3,25 @@ package core
|
|||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/build/fs"
|
"git.akyoto.dev/cli/q/src/build/fs"
|
||||||
"git.akyoto.dev/cli/q/src/build/register"
|
"git.akyoto.dev/cli/q/src/build/register"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/scope"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Function represents the smallest unit of code.
|
// Function represents the smallest unit of code.
|
||||||
type Function struct {
|
type Function struct {
|
||||||
register.Machine
|
register.Machine
|
||||||
Package string
|
Package string
|
||||||
Name string
|
Name string
|
||||||
UniqueName string
|
UniqueName string
|
||||||
File *fs.File
|
File *fs.File
|
||||||
Body []token.Token
|
Body token.List
|
||||||
Functions map[string]*Function
|
Parameters []*scope.Variable
|
||||||
Err error
|
ReturnTypes []types.Type
|
||||||
deferred []func()
|
Functions map[string]*Function
|
||||||
count counter
|
Err error
|
||||||
|
deferred []func()
|
||||||
|
count counter
|
||||||
}
|
}
|
||||||
|
|
||||||
// counter stores how often a certain statement appeared so we can generate a unique label from it.
|
// counter stores how often a certain statement appeared so we can generate a unique label from it.
|
||||||
|
@ -5,35 +5,36 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
"git.akyoto.dev/cli/q/src/build/errors"
|
"git.akyoto.dev/cli/q/src/build/errors"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TokenToRegister moves a token into a register.
|
// TokenToRegister moves a token into a register.
|
||||||
// It only works with identifiers, numbers and strings.
|
// It only works with identifiers, numbers and strings.
|
||||||
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
func (f *Function) TokenToRegister(t token.Token, register cpu.Register) (types.Type, error) {
|
||||||
switch t.Kind {
|
switch t.Kind {
|
||||||
case token.Identifier:
|
case token.Identifier:
|
||||||
name := t.Text(f.File.Bytes)
|
name := t.Text(f.File.Bytes)
|
||||||
variable := f.VariableByName(name)
|
variable := f.VariableByName(name)
|
||||||
|
|
||||||
if variable == nil {
|
if variable == nil {
|
||||||
return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
return types.Invalid, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, t.Position)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.UseVariable(variable)
|
f.UseVariable(variable)
|
||||||
f.SaveRegister(register)
|
f.SaveRegister(register)
|
||||||
f.RegisterRegister(asm.MOVE, register, variable.Register)
|
f.RegisterRegister(asm.MOVE, register, variable.Register)
|
||||||
return nil
|
return variable.Type, nil
|
||||||
|
|
||||||
case token.Number, token.Rune:
|
case token.Number, token.Rune:
|
||||||
number, err := f.Number(t)
|
number, err := f.Number(t)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return types.Invalid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
f.SaveRegister(register)
|
f.SaveRegister(register)
|
||||||
f.RegisterNumber(asm.MOVE, register, number)
|
f.RegisterNumber(asm.MOVE, register, number)
|
||||||
return nil
|
return types.Int, nil
|
||||||
|
|
||||||
case token.String:
|
case token.String:
|
||||||
data := t.Bytes(f.File.Bytes)
|
data := t.Bytes(f.File.Bytes)
|
||||||
@ -41,9 +42,9 @@ func (f *Function) TokenToRegister(t token.Token, register cpu.Register) error {
|
|||||||
label := f.AddBytes(data)
|
label := f.AddBytes(data)
|
||||||
f.SaveRegister(register)
|
f.SaveRegister(register)
|
||||||
f.RegisterLabel(asm.MOVE, register, label)
|
f.RegisterLabel(asm.MOVE, register, label)
|
||||||
return nil
|
return types.Int, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return errors.New(errors.InvalidExpression, f.File, t.Position)
|
return types.Invalid, errors.New(errors.InvalidExpression, f.File, t.Position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ var (
|
|||||||
MissingOperand = &Base{"Missing operand"}
|
MissingOperand = &Base{"Missing operand"}
|
||||||
MissingType = &Base{"Missing type"}
|
MissingType = &Base{"Missing type"}
|
||||||
NotImplemented = &Base{"Not implemented"}
|
NotImplemented = &Base{"Not implemented"}
|
||||||
|
UnknownType = &Base{"Unknown type"}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Base is the base class for errors that have no parameters.
|
// Base is the base class for errors that have no parameters.
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package scanner
|
package scanner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@ -13,6 +12,7 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/fs"
|
"git.akyoto.dev/cli/q/src/build/fs"
|
||||||
"git.akyoto.dev/cli/q/src/build/scope"
|
"git.akyoto.dev/cli/q/src/build/scope"
|
||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// scanFile scans a single file.
|
// scanFile scans a single file.
|
||||||
@ -42,6 +42,8 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
paramsStart = -1
|
paramsStart = -1
|
||||||
paramsEnd = -1
|
paramsEnd = -1
|
||||||
bodyStart = -1
|
bodyStart = -1
|
||||||
|
typeStart = -1
|
||||||
|
typeEnd = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@ -156,9 +158,13 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
|
|
||||||
// Return type
|
// Return type
|
||||||
if i < len(tokens) && tokens[i].Kind == token.ReturnType {
|
if i < len(tokens) && tokens[i].Kind == token.ReturnType {
|
||||||
|
typeStart = i + 1
|
||||||
|
|
||||||
for i < len(tokens) && tokens[i].Kind != token.BlockStart {
|
for i < len(tokens) && tokens[i].Kind != token.BlockStart {
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typeEnd = i
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function definition
|
// Function definition
|
||||||
@ -221,6 +227,11 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
name := tokens[nameStart].Text(contents)
|
name := tokens[nameStart].Text(contents)
|
||||||
body := tokens[bodyStart:i]
|
body := tokens[bodyStart:i]
|
||||||
function := core.NewFunction(pkg, name, file, body)
|
function := core.NewFunction(pkg, name, file, body)
|
||||||
|
|
||||||
|
if typeStart != -1 {
|
||||||
|
function.ReturnTypes = append(function.ReturnTypes, types.New(tokens[typeStart:typeEnd]))
|
||||||
|
}
|
||||||
|
|
||||||
parameters := tokens[paramsStart:paramsEnd]
|
parameters := tokens[paramsStart:paramsEnd]
|
||||||
count := 0
|
count := 0
|
||||||
|
|
||||||
@ -230,8 +241,7 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name := tokens[0].Text(contents)
|
name := tokens[0].Text(contents)
|
||||||
dataType := tokens[1].Text(contents)
|
dataType := types.New(tokens[1:])
|
||||||
fmt.Println(dataType)
|
|
||||||
register := x64.CallRegisters[count]
|
register := x64.CallRegisters[count]
|
||||||
uses := token.Count(function.Body, contents, token.Identifier, name)
|
uses := token.Count(function.Body, contents, token.Identifier, name)
|
||||||
|
|
||||||
@ -241,10 +251,12 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
|
|
||||||
variable := &scope.Variable{
|
variable := &scope.Variable{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
Type: dataType,
|
||||||
Register: register,
|
Register: register,
|
||||||
Alive: uses,
|
Alive: uses,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function.Parameters = append(function.Parameters, variable)
|
||||||
function.AddVariable(variable)
|
function.AddVariable(variable)
|
||||||
count++
|
count++
|
||||||
return nil
|
return nil
|
||||||
@ -258,6 +270,8 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
|||||||
nameStart = -1
|
nameStart = -1
|
||||||
paramsStart = -1
|
paramsStart = -1
|
||||||
bodyStart = -1
|
bodyStart = -1
|
||||||
|
typeStart = -1
|
||||||
|
typeEnd = -1
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,13 @@ package scope
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.akyoto.dev/cli/q/src/build/cpu"
|
"git.akyoto.dev/cli/q/src/build/cpu"
|
||||||
|
"git.akyoto.dev/cli/q/src/build/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variable represents a named register.
|
// Variable represents a named register.
|
||||||
type Variable struct {
|
type Variable struct {
|
||||||
Name string
|
Name string
|
||||||
|
Type types.Type
|
||||||
Alive uint8
|
Alive uint8
|
||||||
Register cpu.Register
|
Register cpu.Register
|
||||||
}
|
}
|
||||||
|
8
src/build/types/New.go
Normal file
8
src/build/types/New.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import "git.akyoto.dev/cli/q/src/build/token"
|
||||||
|
|
||||||
|
// New creates a new type from a list of tokens.
|
||||||
|
func New(tokens token.List) Type {
|
||||||
|
return Int
|
||||||
|
}
|
8
src/build/types/Type.go
Normal file
8
src/build/types/Type.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Invalid Type = iota // Invalid is an invalid type.
|
||||||
|
Int
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user