diff --git a/examples/echo/echo.q b/examples/echo/echo.q new file mode 100644 index 0000000..fb1159e --- /dev/null +++ b/examples/echo/echo.q @@ -0,0 +1,18 @@ +import mem +import sys + +main() { + length := 4096 + address := mem.alloc(length) + + loop { + n := sys.read(0, address, length) + + if n <= 0 { + mem.free(address, length) + return + } + + sys.write(1, address, n) + } +} \ No newline at end of file diff --git a/lib/mem/alloc.q b/lib/mem/alloc.q new file mode 100644 index 0000000..e03ece3 --- /dev/null +++ b/lib/mem/alloc.q @@ -0,0 +1,9 @@ +import sys + +alloc(length) { + return sys.mmap(0, length, 3, 290) +} + +free(address, length) { + return sys.munmap(address, length) +} \ No newline at end of file diff --git a/lib/sys/linux.q b/lib/sys/linux.q index 9c44037..68a8fbf 100644 --- a/lib/sys/linux.q +++ b/lib/sys/linux.q @@ -3,7 +3,7 @@ read(fd, address, length) { } write(fd, address, length) { - syscall(1, fd, address, length) + return syscall(1, fd, address, length) } open(file, flags, mode) { diff --git a/src/build/core/CompileDefinition.go b/src/build/core/CompileDefinition.go index bbc544b..bf215a1 100644 --- a/src/build/core/CompileDefinition.go +++ b/src/build/core/CompileDefinition.go @@ -22,21 +22,7 @@ func (f *Function) CompileDefinition(node *ast.Define) error { return errors.New(&errors.UnusedVariable{Name: name}, f.File, node.Name.Position) } - value := node.Value - - err := value.EachLeaf(func(leaf *expression.Expression) error { - if leaf.Token.Kind == token.Identifier && !f.identifierExists(leaf.Token.Text()) { - return errors.New(&errors.UnknownIdentifier{Name: leaf.Token.Text()}, f.File, leaf.Token.Position) - } - - return nil - }) - - if err != nil { - return err - } - - return f.storeVariableInRegister(name, value, uses) + return f.storeVariableInRegister(name, node.Value, uses) } func (f *Function) AddVariable(variable *Variable) { @@ -94,12 +80,7 @@ func (f *Function) identifierExists(name string) bool { } func (f *Function) storeVariableInRegister(name string, value *expression.Expression, uses int) error { - reg, exists := f.Scope().FindFree(f.cpu.General) - - if !exists { - panic("no free registers") - } - + reg := f.Scope().MustFindFree(f.cpu.General) f.Scope().Reserve(reg) err := f.ExpressionToRegister(value, reg) diff --git a/tests/errors/UnknownIdentifier4.q b/tests/errors/UnknownFunction2.q similarity index 55% rename from tests/errors/UnknownIdentifier4.q rename to tests/errors/UnknownFunction2.q index a7387e2..c31b354 100644 --- a/tests/errors/UnknownIdentifier4.q +++ b/tests/errors/UnknownFunction2.q @@ -1,7 +1,3 @@ main() { x := 1 + f(x) -} - -f(x) { - return x } \ No newline at end of file diff --git a/tests/errors/UnknownIdentifier3.q b/tests/errors/UnknownIdentifier3.q index c31b354..a7387e2 100644 --- a/tests/errors/UnknownIdentifier3.q +++ b/tests/errors/UnknownIdentifier3.q @@ -1,3 +1,7 @@ main() { x := 1 + f(x) +} + +f(x) { + return x } \ No newline at end of file diff --git a/tests/errors_test.go b/tests/errors_test.go index 7782a67..6c08acd 100644 --- a/tests/errors_test.go +++ b/tests/errors_test.go @@ -34,10 +34,10 @@ var errs = []struct { {"MissingOperand2.q", errors.MissingOperand}, {"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}}, {"UnknownFunction.q", &errors.UnknownFunction{Name: "unknown"}}, + {"UnknownFunction2.q", &errors.UnknownFunction{Name: "f"}}, {"UnknownIdentifier.q", &errors.UnknownIdentifier{Name: "x"}}, {"UnknownIdentifier2.q", &errors.UnknownIdentifier{Name: "x"}}, - {"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "f"}}, - {"UnknownIdentifier4.q", &errors.UnknownIdentifier{Name: "x"}}, + {"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "x"}}, {"UnusedVariable.q", &errors.UnusedVariable{Name: "x"}}, } diff --git a/tests/examples_test.go b/tests/examples_test.go index 8af877d..17839db 100644 --- a/tests/examples_test.go +++ b/tests/examples_test.go @@ -9,19 +9,20 @@ import ( ) var examples = []struct { - Name string - ExpectedOutput string - ExpectedExitCode int + Name string + Input string + Output string + ExitCode int }{ - {"hello", "Hello", 0}, - {"factorial", "", 120}, - {"fibonacci", "", 55}, + {"hello", "", "Hello", 0}, + {"factorial", "", "", 120}, + {"fibonacci", "", "", 55}, } func TestExamples(t *testing.T) { for _, test := range examples { t.Run(test.Name, func(t *testing.T) { - run(t, filepath.Join("..", "examples", test.Name), test.ExpectedOutput, test.ExpectedExitCode) + run(t, filepath.Join("..", "examples", test.Name), test.Input, test.Output, test.ExitCode) }) } } diff --git a/tests/programs_test.go b/tests/programs_test.go index aa3a6d5..5d4e5ff 100644 --- a/tests/programs_test.go +++ b/tests/programs_test.go @@ -4,6 +4,7 @@ import ( "os" "os/exec" "path/filepath" + "strings" "testing" "git.akyoto.dev/cli/q/src/build" @@ -11,34 +12,35 @@ import ( ) var programs = []struct { - Name string - ExpectedOutput string - ExpectedExitCode int + Name string + Input string + Output string + ExitCode int }{ - {"empty", "", 0}, - {"math", "", 10}, - {"precedence", "", 10}, - {"square-sum", "", 25}, - {"chained-calls", "", 9}, - {"nested-calls", "", 4}, - {"param", "", 3}, - {"param-multi", "", 21}, - {"reuse", "", 3}, - {"return", "", 6}, - {"reassign", "", 2}, - {"branch", "", 0}, - {"branch-and", "", 0}, - {"branch-or", "", 0}, - {"branch-both", "", 0}, - {"jump-near", "", 0}, - {"loop", "", 0}, - {"loop-lifetime", "", 0}, + {"empty", "", "", 0}, + {"math", "", "", 10}, + {"precedence", "", "", 10}, + {"square-sum", "", "", 25}, + {"chained-calls", "", "", 9}, + {"nested-calls", "", "", 4}, + {"param", "", "", 3}, + {"param-multi", "", "", 21}, + {"reuse", "", "", 3}, + {"return", "", "", 6}, + {"reassign", "", "", 2}, + {"branch", "", "", 0}, + {"branch-and", "", "", 0}, + {"branch-or", "", "", 0}, + {"branch-both", "", "", 0}, + {"jump-near", "", "", 0}, + {"loop", "", "", 0}, + {"loop-lifetime", "", "", 0}, } func TestPrograms(t *testing.T) { for _, test := range programs { t.Run(test.Name, func(t *testing.T) { - run(t, filepath.Join("programs", test.Name+".q"), test.ExpectedOutput, test.ExpectedExitCode) + run(t, filepath.Join("programs", test.Name+".q"), test.Input, test.Output, test.ExitCode) }) } } @@ -57,7 +59,7 @@ func BenchmarkPrograms(b *testing.B) { } // run builds and runs the file to check if the output matches the expected output. -func run(t *testing.T, name string, expectedOutput string, expectedExitCode int) { +func run(t *testing.T, name string, input string, expectedOutput string, expectedExitCode int) { b := build.New(name) assert.True(t, len(b.Executable()) > 0) @@ -72,6 +74,7 @@ func run(t *testing.T, name string, expectedOutput string, expectedExitCode int) assert.True(t, stat.Size() > 0) cmd := exec.Command(b.Executable()) + cmd.Stdin = strings.NewReader(input) output, err := cmd.Output() exitCode := 0