Merge pull request #29 from ThakeeNathees/testing-impl

A small test script added
This commit is contained in:
Thakee Nathees 2021-05-22 18:59:28 +05:30 committed by GitHub
commit 82982d3ceb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 122 deletions

View File

@ -1,12 +1,11 @@
// To implement.
[ ] Resolve function name (called before defined).
[ ] Implement argparse.
[ ] Implement resolve path in cli.
[ ] Structs.
[ ] Implement math library.
[ ] Implement resolve path in cli.
[ ] Single header for embedding.
[ ] Implement fiber from script body and vm run fibers (not scripts).
Then remove vm's root script.

View File

@ -4,12 +4,13 @@
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pocketlang.h"
void errorPrint(PKVM* vm, PKErrorType type, const char* file, int line,
const char* message) {
const char* message) {
if (type == PK_ERROR_COMPILE) {
fprintf(stderr, "Error: %s\n at %s:%i\n", message, file, line);
} else if (type == PK_ERROR_RUNTIME) {
@ -63,9 +64,9 @@ pkStringPtr loadScript(PKVM* vm, const char* path) {
// Read source to buffer.
char* buff = (char*)malloc((size_t)(file_size) + 1);
size_t read = fread(buff, sizeof(char), file_size, file);
// Using read instead of file_size is because "\r\n" is read as '\n' in
// windows the '\r'.
// windows.
size_t read = fread(buff, sizeof(char), file_size, file);
buff[read] = '\0';
fclose(file);
@ -83,12 +84,12 @@ int main(int argc, char** argv) {
"Free and open source software under the terms of the MIT license.\n";
const char* help = "Usage: pocketlang <source_path>\n";
// TODO: implement arg parse.
if (argc < 2) {
printf("%s\n%s", notice, help);
return 0;
}
const char* source_path = argv[1];
pkConfiguration config = pkNewConfiguration();
config.error_fn = errorPrint;
@ -96,9 +97,20 @@ int main(int argc, char** argv) {
config.load_script_fn = loadScript;
config.resolve_path_fn = resolvePath;
PKVM* vm = pkNewVM(&config);
PKInterpretResult result = pkInterpret(vm, source_path);
pkFreeVM(vm);
return result;
// FIXME: this is temp till arg parse implemented.
if (argc >= 3 && strcmp(argv[1], "-c") == 0) {
PKVM* vm = pkNewVM(&config);
PKInterpretResult result = pkInterpretSource(vm, argv[2], "$(Source)");
pkFreeVM(vm);
return result;
} else {
PKVM* vm = pkNewVM(&config);
PKInterpretResult result = pkInterpret(vm, argv[1]);
pkFreeVM(vm);
return result;
}
return 0;
}

View File

@ -691,7 +691,7 @@ static void lexToken(Compiler* compiler) {
eatName(compiler);
} else {
if (c >= 32 && c <= 126) {
lexError(compiler, "Invalid character %c", c);
lexError(compiler, "Invalid character '%c'", c);
} else {
lexError(compiler, "Invalid byte 0x%x", (uint8_t)c);
}
@ -752,15 +752,22 @@ static bool matchLine(Compiler* compiler) {
return true;
}
// Match semi collon, multiple new lines or peek 'end' keyword.
// Match semi collon, multiple new lines or peek 'end', 'else', 'elif'
// keywords.
static bool matchEndStatement(Compiler* compiler) {
if (match(compiler, TK_SEMICOLLON)) {
skipNewLines(compiler);
return true;
}
if (matchLine(compiler) || peek(compiler) == TK_END || peek(compiler) == TK_EOF)
if (matchLine(compiler) || peek(compiler) == TK_EOF)
return true;
// In the below statement we don't require any new lines or semicollons.
// 'if cond then stmnt1 elif cond2 then stmnt2 else stmnt3 end'
if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE ||
peek(compiler) == TK_ELIF)
return true;
return false;
}
@ -1207,7 +1214,7 @@ static void exprChainCall(Compiler* compiler, bool can_assign) {
skipNewLines(compiler);
argc++;
} while (match(compiler, TK_COMMA));
consume(compiler, TK_RBRACE, "Expected '}' after chain call"
consume(compiler, TK_RBRACE, "Expected '}' after chain call "
"parameter list.");
}
}
@ -1263,7 +1270,7 @@ static void exprGrouping(Compiler* compiler, bool can_assign) {
skipNewLines(compiler);
compileExpression(compiler);
skipNewLines(compiler);
consume(compiler, TK_RPARAN, "Expected ')' after expression ");
consume(compiler, TK_RPARAN, "Expected ')' after expression.");
}
static void exprList(Compiler* compiler, bool can_assign) {
@ -1699,7 +1706,7 @@ static int compileFunction(Compiler* compiler, FuncType fn_type) {
}
}
if (predefined)
parseError(compiler, "Multiple definition of a parameter");
parseError(compiler, "Multiple definition of a parameter.");
compilerAddVariable(compiler, param_name, param_len,
compiler->previous.line);
@ -1783,6 +1790,11 @@ static Script* importFile(Compiler* compiler, const char* path) {
resolved = vm->config.resolve_path_fn(vm, compiler->script->path->data, path);
}
if (resolved.string == NULL) {
parseError(compiler, "Cannot resolve path '%s' from '%s'", path,
compiler->script->path->data);
}
// Create new string for the resolved path. And free the resolved path.
int index = (int)scriptAddName(compiler->script, compiler->vm,
resolved.string, (uint32_t)strlen(resolved.string));
@ -1952,7 +1964,8 @@ L_import_done:
// from module import symbol [as alias [, symbol2 [as alias]]]
static void compileFromImport(Compiler* compiler) {
// Import the library and push it on the stack.
// Import the library and push it on the stack. If the import failed
// lib_from would be NULL.
Script* lib_from = compilerImport(compiler);
// At this point the script would be on the stack before executing the next
@ -1961,7 +1974,7 @@ static void compileFromImport(Compiler* compiler) {
if (match(compiler, TK_STAR)) {
// from math import *
compilerImportAll(compiler, lib_from);
if (lib_from) compilerImportAll(compiler, lib_from);
} else {
do {
@ -2010,7 +2023,10 @@ static void compileFromImport(Compiler* compiler) {
static void compileRegularImport(Compiler* compiler) {
do {
// Import the library and push it on the stack.
// Import the library and push it on the stack. If it cannot import
// the lib would be null, but we're not terminating here, just continue
// parsing for cascaded errors.
Script* lib = compilerImport(compiler);
// variable to bind the imported script.
@ -2034,7 +2050,7 @@ static void compileRegularImport(Compiler* compiler) {
// If it has a module name use it as binding variable.
// Core libs names are it's module name but for local libs it's optional
// to define a module name for a script.
if (lib->moudle != NULL) {
if (lib && lib->moudle != NULL) {
// Get the variable to bind the imported symbol, if we already have a
// variable with that name override it, otherwise use a new variable.
@ -2057,7 +2073,7 @@ static void compileRegularImport(Compiler* compiler) {
emitOpcode(compiler, OP_POP);
} else {
compilerImportAll(compiler, lib);
if (lib) compilerImportAll(compiler, lib);
// Done importing everything from lib now pop the lib.
emitOpcode(compiler, OP_POP);
}

View File

@ -15,3 +15,11 @@ l1[1] = true; assert(l1[1], 'List subscript set failed.')
h1 = hash("testing"); h2 = hash("test" + "ing")
assert(h1 == h2, 'Hash function failed.')
assert(to_string(42) == '42', 'to_string() failed.')
## Logical statement test
val = 0; a = false; b = true
get_true = func return true end
if a and b then assert(false) end
if a or b then val = 42 else assert(false) end assert(val == 42)
if get_true() or false then val = 12 end assert(val == 12)

View File

@ -1,27 +0,0 @@
## Chain call tests.
# concatenative programming
def fn1(data)
return '[fn1:' + data + ']'
end
def fn2(data, suffix)
return '[fn2:' + data + '|' + suffix + ']'
end
def fn3(data)
return '[fn3:' + data + ']'
end
result = 'data' -> fn1 -> fn2{'suff'} -> fn3
## `result -> print` same as `print(result)`
assert(result == '[fn3:[fn2:[fn1:data]|suff]]')
result = ' tEST+InG ' -> str_strip -> str_lower
assert(result == 'test+ing')

View File

@ -1,21 +1,26 @@
# Function Tests. (TODO: add more)
## Function Tests.
def f1 return 'f1' end
assert(f1() == 'f1')
def f2() return 'f2' end
assert(f2() == 'f2')
def f3(a, b, c, d)
return c
end
def f1 return 'f1' end assert(f1() == 'f1')
def f2() return 'f2' end assert(f2() == 'f2')
def f3(a, b, c, d) return c end
assert(f3('a', 'b', 'c', 'd') == 'c')
# forward call.
## Forward call.
val = before_defn()
def before_defn()
return 'defined after the call'
end
assert(val == 'defined after the call')
## Chain call tests. (concatenative programming)
def fn1(data) return '[fn1:' + data + ']' end
def fn2(data, suffix) return '[fn2:' + data + '|' + suffix + ']' end
def fn3(data) return '[fn3:' + data + ']' end
result = 'data' -> fn1 -> fn2{'suff'} -> fn3
assert(result == '[fn3:[fn2:[fn1:data]|suff]]')
result = ' tEST+InG ' -> str_strip -> str_lower
assert(result == 'test+ing')

View File

@ -3,8 +3,7 @@
variable = null ## Will be changed by the control flow.
unreachable = func assert(false, 'Unreachable') end
if true then variable = 42
else unreachable() end
if true then variable = 42 else unreachable() end
assert(variable == 42, 'If statement failed.')
if false then unreachable()

View File

@ -1,18 +0,0 @@
## Logical statement test
val = 0
a = false; b = true;
if a and b then assert(false) end
if a or b then val = 42
else assert(false) end
assert(val == 42)
get_true = func return true end
if get_true() or false
val = 12
end
assert(val == 12)

40
test/run.py Normal file
View File

@ -0,0 +1,40 @@
import subprocess
import json, os
files = [
"lang/basics.pk",
"lang/functions.pk",
"lang/if.pk",
"examples/fib.pk",
"examples/prime.pk",
]
FMT_PATH = "%-25s"
INDENTATION = ' | '
def run_all_tests():
for path in files:
run_file(path)
def run_file(path):
print(FMT_PATH % path, end='')
result = run_command(['pocket', path])
if result.returncode != 0:
print('-- Failed')
err = INDENTATION + result.stderr \
.decode('utf8') \
.replace('\n', '\n' + INDENTATION)
print(err)
else:
print('-- OK')
def run_command(command):
return subprocess.run(command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
run_all_tests()

View File

@ -1,39 +0,0 @@
@echo off
:: Resolve path hasn't implemented.
cd lang
echo Testing "import.pk"
pocket import.pk
if %errorlevel% neq 0 goto :FAILED
cd ..
set files=( ^
lang\basics.pk ^
lang\if.pk ^
lang\logical.pk ^
lang\chain_call.pk ^
^
examples\fib.pk ^
examples\prime.pk ^
)
set errorlevel=0
for %%f in %files% do (
echo Testing %%f
pocket %%f
if %errorlevel% neq 0 goto :FAILED
)
goto :SUCCESS
:FAILED
echo.
echo Test failed.
goto :END
:SUCCESS
echo.
echo All tests were passed.
goto :END
:END