Implemented extern functions
This commit is contained in:
parent
1083db6ab2
commit
3b66dae1d4
@ -1,3 +1,7 @@
|
||||
extern user32 {
|
||||
MessageBoxA(window *Any, text *Int8, title *Int8, type UInt)
|
||||
}
|
||||
|
||||
main() {
|
||||
title := "Title."
|
||||
text := "Hi!"
|
||||
|
12
lib/io/io.q
12
lib/io/io.q
@ -4,18 +4,18 @@ in(buffer []Int8) -> Int {
|
||||
return sys.read(0, buffer, len(buffer))
|
||||
}
|
||||
|
||||
out(message []Int8) -> Int {
|
||||
return sys.write(1, message, len(message))
|
||||
out(buffer []Int8) -> Int {
|
||||
return sys.write(1, buffer, len(buffer))
|
||||
}
|
||||
|
||||
error(message []Int8) -> Int {
|
||||
return sys.write(2, message, len(message))
|
||||
error(buffer []Int8) -> Int {
|
||||
return sys.write(2, buffer, len(buffer))
|
||||
}
|
||||
|
||||
read(fd Int, buffer []Int8) -> Int {
|
||||
return sys.read(fd, buffer, len(buffer))
|
||||
}
|
||||
|
||||
write(fd Int, message []Int8) -> Int {
|
||||
return sys.write(fd, message, len(message))
|
||||
write(fd Int, buffer []Int8) -> Int {
|
||||
return sys.write(fd, buffer, len(buffer))
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
read(fd Int, address *Any, length Int) -> Int {
|
||||
return syscall(0, fd, address, length)
|
||||
read(fd Int, buffer *Any, length Int) -> Int {
|
||||
return syscall(0, fd, buffer, length)
|
||||
}
|
||||
|
||||
write(fd Int, address *Any, length Int) -> Int {
|
||||
return syscall(1, fd, address, length)
|
||||
write(fd Int, buffer *Any, length Int) -> Int {
|
||||
return syscall(1, fd, buffer, length)
|
||||
}
|
||||
|
||||
open(path *Any, flags Int, mode Int) -> Int {
|
||||
|
@ -1,9 +1,9 @@
|
||||
read(fd Int, address *Any, length Int) -> Int {
|
||||
return syscall(0x2000003, fd, address, length)
|
||||
read(fd Int, buffer *Any, length Int) -> Int {
|
||||
return syscall(0x2000003, fd, buffer, length)
|
||||
}
|
||||
|
||||
write(fd Int, address *Any, length Int) -> Int {
|
||||
return syscall(0x2000004, fd, address, length)
|
||||
write(fd Int, buffer *Any, length Int) -> Int {
|
||||
return syscall(0x2000004, fd, buffer, length)
|
||||
}
|
||||
|
||||
open(path *Any, flags Int, mode Int) -> Int {
|
||||
|
@ -1,10 +1,16 @@
|
||||
read(fd Int, address *Any, length Int) -> Int {
|
||||
kernel32.ReadFile(fd, address, length)
|
||||
extern kernel32 {
|
||||
GetStdHandle(handle Int) -> Int
|
||||
WriteConsoleA(fd Int, buffer *Any, length Int, written *Int) -> Bool
|
||||
ReadFile(fd Int, buffer *Any, length Int) -> Bool
|
||||
}
|
||||
|
||||
read(fd Int, buffer *Any, length Int) -> Int {
|
||||
kernel32.ReadFile(fd, buffer, length)
|
||||
return length
|
||||
}
|
||||
|
||||
write(fd Int, address *Any, length Int) -> Int {
|
||||
write(fd Int, buffer *Any, length Int) -> Int {
|
||||
fd = kernel32.GetStdHandle(-10 - fd)
|
||||
kernel32.WriteConsoleA(fd, address, length, 0)
|
||||
kernel32.WriteConsoleA(fd, buffer, length, 0)
|
||||
return length
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
extern kernel32 {
|
||||
VirtualAlloc(address Int, length Int, flags Int, protection Int)
|
||||
VirtualFree(address *Any, length Int, type Int) -> Bool
|
||||
}
|
||||
|
||||
mmap(address Int, length Int, protection Int, flags Int) -> *Any {
|
||||
return kernel32.VirtualAlloc(address, length, flags, protection)
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
extern kernel32 {
|
||||
ExitProcess(code UInt)
|
||||
}
|
||||
|
||||
exit(code Int) {
|
||||
kernel32.ExitProcess(code)
|
||||
}
|
@ -108,6 +108,10 @@ func CompileFunctions(functions map[string]*core.Function) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
for _, function := range functions {
|
||||
if function.IsExtern() {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
|
32
src/core/BeforeCall.go
Normal file
32
src/core/BeforeCall.go
Normal file
@ -0,0 +1,32 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/cpu"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
"git.akyoto.dev/cli/q/src/types"
|
||||
)
|
||||
|
||||
// BeforeCall loads the registers with the parameter values and checks that the types match with the function signature.
|
||||
func (f *Function) BeforeCall(fn *Function, parameters []*expression.Expression, registers []cpu.Register) error {
|
||||
for i := len(parameters) - 1; i >= 0; i-- {
|
||||
typ, err := f.ExpressionToRegister(parameters[i], registers[i])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !types.Is(typ, fn.Input[i].Type) {
|
||||
_, expectsPointer := fn.Input[i].Type.(*types.Pointer)
|
||||
|
||||
if expectsPointer && parameters[i].Token.Kind == token.Number && parameters[i].Token.Text(f.File.Bytes) == "0" {
|
||||
continue
|
||||
}
|
||||
|
||||
return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: fn.Input[i].Type.Name(), ParameterName: fn.Input[i].Name}, f.File, parameters[i].Token.Position)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/expression"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
"git.akyoto.dev/cli/q/src/types"
|
||||
"git.akyoto.dev/cli/q/src/x86"
|
||||
)
|
||||
@ -48,22 +47,13 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
|
||||
name = nameNode.Token.Text(f.File.Bytes)
|
||||
}
|
||||
|
||||
if pkg == "kernel32" || pkg == "user32" || pkg == "gdi32" || pkg == "comctl32" {
|
||||
parameters := root.Children[1:]
|
||||
registers := x86.WindowsInputRegisters[:len(parameters)]
|
||||
fn, exists = f.Functions[pkg+"."+name]
|
||||
|
||||
for i := len(parameters) - 1; i >= 0; i-- {
|
||||
_, err := f.ExpressionToRegister(parameters[i], registers[i])
|
||||
if !exists {
|
||||
return nil, errors.New(&errors.UnknownFunction{Name: name}, f.File, nameNode.Token.Position)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
f.DLLs = f.DLLs.Append(pkg, name)
|
||||
f.DLLCall(fmt.Sprintf("%s.%s", pkg, name))
|
||||
return nil, nil
|
||||
} else if pkg != f.File.Package {
|
||||
if pkg != f.File.Package && !fn.IsExtern() {
|
||||
if f.File.Imports == nil {
|
||||
return nil, errors.New(&errors.UnknownPackage{Name: pkg}, f.File, pkgNode.Token.Position)
|
||||
}
|
||||
@ -77,36 +67,30 @@ func (f *Function) CompileCall(root *expression.Expression) ([]types.Type, error
|
||||
imp.Used = true
|
||||
}
|
||||
|
||||
fn, exists = f.Functions[pkg+"."+name]
|
||||
|
||||
if !exists {
|
||||
return nil, errors.New(&errors.UnknownFunction{Name: name}, f.File, nameNode.Token.Position)
|
||||
}
|
||||
|
||||
parameters := root.Children[1:]
|
||||
|
||||
if len(parameters) != len(fn.Input) {
|
||||
return nil, errors.New(&errors.ParameterCountMismatch{Function: fn.Name, Count: len(parameters), ExpectedCount: len(fn.Input)}, f.File, nameNode.Token.End())
|
||||
}
|
||||
|
||||
registers := f.CPU.Input[:len(parameters)]
|
||||
|
||||
for i := len(parameters) - 1; i >= 0; i-- {
|
||||
typ, err := f.ExpressionToRegister(parameters[i], registers[i])
|
||||
if fn.IsExtern() {
|
||||
f.DLLs = f.DLLs.Append(pkg, name)
|
||||
registers := x86.WindowsInputRegisters[:len(parameters)]
|
||||
err := f.BeforeCall(fn, parameters, registers)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !types.Is(typ, fn.Input[i].Type) {
|
||||
_, expectsPointer := fn.Input[i].Type.(*types.Pointer)
|
||||
f.DLLCall(fmt.Sprintf("%s.%s", pkg, name))
|
||||
return fn.OutputTypes, nil
|
||||
}
|
||||
|
||||
if expectsPointer && parameters[i].Token.Kind == token.Number && parameters[i].Token.Text(f.File.Bytes) == "0" {
|
||||
continue
|
||||
}
|
||||
registers := f.CPU.Input[:len(parameters)]
|
||||
err := f.BeforeCall(fn, parameters, registers)
|
||||
|
||||
return nil, errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: fn.Input[i].Type.Name(), ParameterName: fn.Input[i].Name}, f.File, parameters[i].Token.Position)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.CallSafe(fn, registers)
|
||||
|
6
src/core/IsExtern.go
Normal file
6
src/core/IsExtern.go
Normal file
@ -0,0 +1,6 @@
|
||||
package core
|
||||
|
||||
// IsExtern returns true if the function has no body.
|
||||
func (f *Function) IsExtern() bool {
|
||||
return f.Body == nil
|
||||
}
|
@ -19,6 +19,10 @@ func (f *Function) ResolveTypes() error {
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||
}
|
||||
|
||||
if f.IsExtern() {
|
||||
continue
|
||||
}
|
||||
|
||||
uses := token.Count(f.Body, f.File.Bytes, token.Identifier, param.Name)
|
||||
|
||||
if uses == 0 && param.Name != "_" {
|
||||
@ -38,7 +42,7 @@ func (f *Function) ResolveTypes() error {
|
||||
param.Type = types.ByName(typeName, f.Package, f.Structs)
|
||||
|
||||
if param.Type == nil {
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[1].Position)
|
||||
return errors.New(&errors.UnknownType{Name: typeName}, f.File, param.tokens[0].Position)
|
||||
}
|
||||
|
||||
f.OutputTypes = append(f.OutputTypes, param.Type)
|
||||
|
@ -9,6 +9,7 @@ var (
|
||||
ExpectedIfBeforeElse = &Base{"Expected an 'if' block before 'else'"}
|
||||
ExpectedPackageName = &Base{"Expected package name"}
|
||||
ExpectedStructName = &Base{"Expected struct name"}
|
||||
ExpectedDLLName = &Base{"Expected DLL name"}
|
||||
InvalidNumber = &Base{"Invalid number"}
|
||||
InvalidExpression = &Base{"Invalid expression"}
|
||||
InvalidRune = &Base{"Invalid rune"}
|
||||
|
54
src/scanner/scanExtern.go
Normal file
54
src/scanner/scanExtern.go
Normal file
@ -0,0 +1,54 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// scanExtern scans a block of external function declarations.
|
||||
func (s *Scanner) scanExtern(file *fs.File, tokens token.List, i int) (int, error) {
|
||||
i++
|
||||
|
||||
if tokens[i].Kind != token.Identifier {
|
||||
return i, errors.New(errors.ExpectedDLLName, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
dllName := tokens[i].Text(file.Bytes)
|
||||
i++
|
||||
|
||||
if tokens[i].Kind != token.BlockStart {
|
||||
return i, errors.New(errors.MissingBlockStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
i++
|
||||
closed := false
|
||||
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.Identifier {
|
||||
function, j, err := scanFunctionSignature(file, tokens, i, token.NewLine)
|
||||
|
||||
if err != nil {
|
||||
return j, err
|
||||
}
|
||||
|
||||
i = j
|
||||
function.Package = dllName
|
||||
function.UniqueName = dllName + "." + function.Name
|
||||
s.functions <- function
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.BlockEnd {
|
||||
closed = true
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
if !closed {
|
||||
return i, errors.New(errors.MissingBlockEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
@ -37,6 +37,8 @@ func (s *Scanner) scanFile(path string, pkg string) error {
|
||||
i, err = s.scanStruct(file, tokens, i)
|
||||
case token.Identifier:
|
||||
i, err = s.scanFunction(file, tokens, i)
|
||||
case token.Extern:
|
||||
i, err = s.scanExtern(file, tokens, i)
|
||||
case token.EOF:
|
||||
return nil
|
||||
case token.Invalid:
|
||||
|
@ -1,7 +1,6 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/core"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
@ -9,84 +8,17 @@ import (
|
||||
|
||||
// scanFunction scans a function.
|
||||
func (s *Scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, error) {
|
||||
function, i, err := scanFunctionSignature(file, tokens, i, token.BlockStart)
|
||||
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
var (
|
||||
groupLevel = 0
|
||||
blockLevel = 0
|
||||
nameStart = i
|
||||
paramsStart = -1
|
||||
paramsEnd = -1
|
||||
bodyStart = -1
|
||||
typeStart = -1
|
||||
typeEnd = -1
|
||||
blockLevel = 0
|
||||
bodyStart = -1
|
||||
)
|
||||
|
||||
i++
|
||||
|
||||
// Function parameters
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.GroupStart {
|
||||
groupLevel++
|
||||
i++
|
||||
|
||||
if groupLevel == 1 {
|
||||
paramsStart = i
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.GroupEnd {
|
||||
groupLevel--
|
||||
|
||||
if groupLevel < 0 {
|
||||
return i, errors.New(errors.MissingGroupStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if groupLevel == 0 {
|
||||
paramsEnd = i
|
||||
i++
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.Invalid {
|
||||
return i, errors.New(&errors.InvalidCharacter{Character: tokens[i].Text(file.Bytes)}, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.EOF {
|
||||
if groupLevel > 0 {
|
||||
return i, errors.New(errors.MissingGroupEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if paramsStart == -1 {
|
||||
return i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
|
||||
if groupLevel > 0 {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
return i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
// Return type
|
||||
if i < len(tokens) && tokens[i].Kind == token.ReturnType {
|
||||
typeStart = i + 1
|
||||
|
||||
for i < len(tokens) && tokens[i].Kind != token.BlockStart {
|
||||
i++
|
||||
}
|
||||
|
||||
typeEnd = i
|
||||
}
|
||||
|
||||
// Function definition
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.ReturnType {
|
||||
@ -144,47 +76,7 @@ func (s *Scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, er
|
||||
return i, errors.New(errors.ExpectedFunctionDefinition, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
name := tokens[nameStart].Text(file.Bytes)
|
||||
body := tokens[bodyStart:i]
|
||||
function := core.NewFunction(file.Package, name, file, body)
|
||||
|
||||
if typeStart != -1 {
|
||||
if tokens[typeStart].Kind == token.GroupStart && tokens[typeEnd-1].Kind == token.GroupEnd {
|
||||
typeStart++
|
||||
typeEnd--
|
||||
}
|
||||
|
||||
outputTokens := tokens[typeStart:typeEnd]
|
||||
|
||||
err := outputTokens.Split(func(tokens token.List) error {
|
||||
function.Output = append(function.Output, core.NewOutput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
parameters := tokens[paramsStart:paramsEnd]
|
||||
|
||||
err := parameters.Split(func(tokens token.List) error {
|
||||
if len(tokens) == 0 {
|
||||
return errors.New(errors.MissingParameter, file, parameters[0].Position)
|
||||
}
|
||||
|
||||
if len(tokens) == 1 {
|
||||
return errors.New(errors.MissingType, file, tokens[0].End())
|
||||
}
|
||||
|
||||
function.Input = append(function.Input, core.NewInput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
function.Body = tokens[bodyStart:i]
|
||||
s.functions <- function
|
||||
i++
|
||||
return i, nil
|
||||
|
125
src/scanner/scanFunctionSignature.go
Normal file
125
src/scanner/scanFunctionSignature.go
Normal file
@ -0,0 +1,125 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"git.akyoto.dev/cli/q/src/core"
|
||||
"git.akyoto.dev/cli/q/src/errors"
|
||||
"git.akyoto.dev/cli/q/src/fs"
|
||||
"git.akyoto.dev/cli/q/src/token"
|
||||
)
|
||||
|
||||
// scanFunctionSignature scans a function declaration without the body.
|
||||
func scanFunctionSignature(file *fs.File, tokens token.List, i int, delimiter token.Kind) (*core.Function, int, error) {
|
||||
var (
|
||||
groupLevel = 0
|
||||
nameStart = i
|
||||
paramsStart = -1
|
||||
paramsEnd = -1
|
||||
typeStart = -1
|
||||
typeEnd = -1
|
||||
)
|
||||
|
||||
i++
|
||||
|
||||
// Function parameters
|
||||
for i < len(tokens) {
|
||||
if tokens[i].Kind == token.GroupStart {
|
||||
groupLevel++
|
||||
i++
|
||||
|
||||
if groupLevel == 1 {
|
||||
paramsStart = i
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.GroupEnd {
|
||||
groupLevel--
|
||||
|
||||
if groupLevel < 0 {
|
||||
return nil, i, errors.New(errors.MissingGroupStart, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if groupLevel == 0 {
|
||||
paramsEnd = i
|
||||
i++
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.Invalid {
|
||||
return nil, i, errors.New(&errors.InvalidCharacter{Character: tokens[i].Text(file.Bytes)}, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if tokens[i].Kind == token.EOF {
|
||||
if groupLevel > 0 {
|
||||
return nil, i, errors.New(errors.MissingGroupEnd, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
if paramsStart == -1 {
|
||||
return nil, i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
return nil, i, nil
|
||||
}
|
||||
|
||||
if groupLevel > 0 {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, i, errors.New(errors.ExpectedFunctionParameters, file, tokens[i].Position)
|
||||
}
|
||||
|
||||
// Return type
|
||||
if i < len(tokens) && tokens[i].Kind == token.ReturnType {
|
||||
typeStart = i + 1
|
||||
|
||||
for i < len(tokens) && tokens[i].Kind != delimiter {
|
||||
i++
|
||||
}
|
||||
|
||||
typeEnd = i
|
||||
}
|
||||
|
||||
name := tokens[nameStart].Text(file.Bytes)
|
||||
function := core.NewFunction(file.Package, name, file, nil)
|
||||
|
||||
if typeStart != -1 {
|
||||
if tokens[typeStart].Kind == token.GroupStart && tokens[typeEnd-1].Kind == token.GroupEnd {
|
||||
typeStart++
|
||||
typeEnd--
|
||||
}
|
||||
|
||||
outputTokens := tokens[typeStart:typeEnd]
|
||||
|
||||
err := outputTokens.Split(func(tokens token.List) error {
|
||||
function.Output = append(function.Output, core.NewOutput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, i, err
|
||||
}
|
||||
}
|
||||
|
||||
parameters := tokens[paramsStart:paramsEnd]
|
||||
|
||||
err := parameters.Split(func(tokens token.List) error {
|
||||
if len(tokens) == 0 {
|
||||
return errors.New(errors.MissingParameter, file, parameters[0].Position)
|
||||
}
|
||||
|
||||
if len(tokens) == 1 {
|
||||
return errors.New(errors.MissingType, file, tokens[0].End())
|
||||
}
|
||||
|
||||
function.Input = append(function.Input, core.NewInput(tokens))
|
||||
return nil
|
||||
})
|
||||
|
||||
return function, i, err
|
||||
}
|
@ -66,6 +66,7 @@ const (
|
||||
___KEYWORDS___ // <keywords>
|
||||
Assert // assert
|
||||
Else // else
|
||||
Extern // extern
|
||||
If // if
|
||||
Import // import
|
||||
Loop // loop
|
||||
|
@ -25,13 +25,14 @@ func TestFunction(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestKeyword(t *testing.T) {
|
||||
tokens := token.Tokenize([]byte("assert if import else loop return struct switch"))
|
||||
tokens := token.Tokenize([]byte("assert if import else extern loop return struct switch"))
|
||||
|
||||
expected := []token.Kind{
|
||||
token.Assert,
|
||||
token.If,
|
||||
token.Import,
|
||||
token.Else,
|
||||
token.Extern,
|
||||
token.Loop,
|
||||
token.Return,
|
||||
token.Struct,
|
||||
|
@ -19,6 +19,8 @@ func identifier(tokens List, buffer []byte, i Position) (List, Position) {
|
||||
kind = If
|
||||
case "else":
|
||||
kind = Else
|
||||
case "extern":
|
||||
kind = Extern
|
||||
case "import":
|
||||
kind = Import
|
||||
case "loop":
|
||||
|
@ -31,6 +31,8 @@ func ByName(name string, pkg string, structs map[string]*Struct) Type {
|
||||
switch name {
|
||||
case "Any":
|
||||
return Any
|
||||
case "Bool":
|
||||
return Bool
|
||||
case "Int":
|
||||
return Int
|
||||
case "Int64":
|
||||
@ -47,6 +49,8 @@ func ByName(name string, pkg string, structs map[string]*Struct) Type {
|
||||
return Float64
|
||||
case "Float32":
|
||||
return Float32
|
||||
case "UInt":
|
||||
return UInt
|
||||
}
|
||||
|
||||
typ, exists := structs[pkg+"."+name]
|
||||
|
@ -13,6 +13,8 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
Bool = Int
|
||||
Int = Int64
|
||||
Float = Float64
|
||||
UInt = Int
|
||||
)
|
||||
|
1
tests/errors/ExpectedDLLName.q
Normal file
1
tests/errors/ExpectedDLLName.q
Normal file
@ -0,0 +1 @@
|
||||
extern {}
|
@ -15,6 +15,7 @@ var errs = []struct {
|
||||
ExpectedError error
|
||||
}{
|
||||
{"EmptySwitch.q", errors.EmptySwitch},
|
||||
{"ExpectedDLLName.q", errors.ExpectedDLLName},
|
||||
{"ExpectedFunctionDefinition.q", errors.ExpectedFunctionDefinition},
|
||||
{"ExpectedFunctionParameters.q", errors.ExpectedFunctionParameters},
|
||||
{"ExpectedIfBeforeElse.q", errors.ExpectedIfBeforeElse},
|
||||
|
Loading…
x
Reference in New Issue
Block a user