mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
Merge pull request #203 from ThakeeNathees/syntax-change
function and else if keywords are changed.
This commit is contained in:
commit
2262089948
@ -115,7 +115,7 @@ typedef enum {
|
||||
TK_AS, // as
|
||||
TK_DEF, // def
|
||||
TK_NATIVE, // native (C function declaration)
|
||||
TK_FUNC, // func (literal function)
|
||||
TK_FUNCTION, // function (literal function)
|
||||
TK_END, // end
|
||||
|
||||
TK_NULL, // null
|
||||
@ -131,7 +131,6 @@ typedef enum {
|
||||
TK_WHILE, // while
|
||||
TK_FOR, // for
|
||||
TK_IF, // if
|
||||
TK_ELSIF, // elsif
|
||||
TK_ELSE, // else
|
||||
TK_BREAK, // break
|
||||
TK_CONTINUE, // continue
|
||||
@ -178,7 +177,7 @@ static _Keyword _keywords[] = {
|
||||
{ "as", 2, TK_AS },
|
||||
{ "def", 3, TK_DEF },
|
||||
{ "native", 6, TK_NATIVE },
|
||||
{ "func", 4, TK_FUNC },
|
||||
{ "function", 8, TK_FUNCTION },
|
||||
{ "end", 3, TK_END },
|
||||
{ "null", 4, TK_NULL },
|
||||
{ "in", 2, TK_IN },
|
||||
@ -192,7 +191,6 @@ static _Keyword _keywords[] = {
|
||||
{ "while", 5, TK_WHILE },
|
||||
{ "for", 3, TK_FOR },
|
||||
{ "if", 2, TK_IF },
|
||||
{ "elsif", 5, TK_ELSIF },
|
||||
{ "else", 4, TK_ELSE },
|
||||
{ "break", 5, TK_BREAK },
|
||||
{ "continue", 8, TK_CONTINUE },
|
||||
@ -1180,8 +1178,7 @@ static void skipNewLines(Compiler* compiler) {
|
||||
matchLine(compiler);
|
||||
}
|
||||
|
||||
// Match semi collon, multiple new lines or peek 'end', 'else', 'elsif'
|
||||
// keywords.
|
||||
// Match semi collon, multiple new lines or peek 'end', 'else' keywords.
|
||||
static bool matchEndStatement(Compiler* compiler) {
|
||||
if (match(compiler, TK_SEMICOLLON)) {
|
||||
skipNewLines(compiler);
|
||||
@ -1191,9 +1188,8 @@ static bool matchEndStatement(Compiler* compiler) {
|
||||
return true;
|
||||
|
||||
// In the below statement we don't require any new lines or semicolons.
|
||||
// 'if cond then stmnt1 elsif cond2 then stmnt2 else stmnt3 end'
|
||||
if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE ||
|
||||
peek(compiler) == TK_ELSIF)
|
||||
// 'if cond then stmnt1 else if cond2 then stmnt2 else stmnt3 end'
|
||||
if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -1433,7 +1429,7 @@ static void compileExpression(Compiler* compiler);
|
||||
|
||||
static void exprLiteral(Compiler* compiler);
|
||||
static void exprInterpolation(Compiler* compiler);
|
||||
static void exprFunc(Compiler* compiler);
|
||||
static void exprFunction(Compiler* compiler);
|
||||
static void exprName(Compiler* compiler);
|
||||
|
||||
static void exprOr(Compiler* compiler);
|
||||
@ -1509,7 +1505,7 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
||||
/* TK_AS */ NO_RULE,
|
||||
/* TK_DEF */ NO_RULE,
|
||||
/* TK_EXTERN */ NO_RULE,
|
||||
/* TK_FUNC */ { exprFunc, NULL, NO_INFIX },
|
||||
/* TK_FUNCTION */ { exprFunction, NULL, NO_INFIX },
|
||||
/* TK_END */ NO_RULE,
|
||||
/* TK_NULL */ { exprValue, NULL, NO_INFIX },
|
||||
/* TK_IN */ { NULL, exprBinaryOp, PREC_TEST },
|
||||
@ -1523,7 +1519,6 @@ GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
||||
/* TK_WHILE */ NO_RULE,
|
||||
/* TK_FOR */ NO_RULE,
|
||||
/* TK_IF */ NO_RULE,
|
||||
/* TK_ELSIF */ NO_RULE,
|
||||
/* TK_ELSE */ NO_RULE,
|
||||
/* TK_BREAK */ NO_RULE,
|
||||
/* TK_CONTINUE */ NO_RULE,
|
||||
@ -1676,7 +1671,7 @@ static void exprInterpolation(Compiler* compiler) {
|
||||
|
||||
}
|
||||
|
||||
static void exprFunc(Compiler* compiler) {
|
||||
static void exprFunction(Compiler* compiler) {
|
||||
compileFunction(compiler, true);
|
||||
}
|
||||
|
||||
@ -2489,8 +2484,8 @@ static void compileBlockBody(Compiler* compiler, BlockType type) {
|
||||
}
|
||||
|
||||
TokenType next = peek(compiler);
|
||||
while (!(next == TK_END || next == TK_EOF || (
|
||||
(type == BLOCK_IF) && (next == TK_ELSE || next == TK_ELSIF)))) {
|
||||
while (!(next == TK_END || next == TK_EOF ||
|
||||
((type == BLOCK_IF) && (next == TK_ELSE)))) {
|
||||
|
||||
compileStatement(compiler);
|
||||
skipNewLines(compiler);
|
||||
@ -2849,7 +2844,7 @@ static void compileExpression(Compiler* compiler) {
|
||||
parsePrecedence(compiler, PREC_LOWEST);
|
||||
}
|
||||
|
||||
static void compileIfStatement(Compiler* compiler, bool elsif) {
|
||||
static void compileIfStatement(Compiler* compiler, bool else_if) {
|
||||
|
||||
skipNewLines(compiler);
|
||||
compileExpression(compiler); //< Condition.
|
||||
@ -2858,38 +2853,40 @@ static void compileIfStatement(Compiler* compiler, bool elsif) {
|
||||
|
||||
compileBlockBody(compiler, BLOCK_IF);
|
||||
|
||||
if (match(compiler, TK_ELSIF)) {
|
||||
if (match(compiler, TK_ELSE)) {
|
||||
|
||||
// Jump pass else.
|
||||
emitOpcode(compiler, OP_JUMP);
|
||||
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
||||
if (match(compiler, TK_IF)) { //< Compile 'else if'.
|
||||
// Jump pass else.
|
||||
emitOpcode(compiler, OP_JUMP);
|
||||
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
||||
|
||||
// if (false) jump here.
|
||||
patchJump(compiler, ifpatch);
|
||||
// if (false) jump here.
|
||||
patchJump(compiler, ifpatch);
|
||||
|
||||
compilerEnterBlock(compiler);
|
||||
compileIfStatement(compiler, true);
|
||||
compilerExitBlock(compiler);
|
||||
compilerEnterBlock(compiler);
|
||||
compileIfStatement(compiler, true);
|
||||
compilerExitBlock(compiler);
|
||||
|
||||
patchJump(compiler, exit_jump);
|
||||
patchJump(compiler, exit_jump);
|
||||
|
||||
} else if (match(compiler, TK_ELSE)) {
|
||||
} else { //< Compile 'else'.
|
||||
|
||||
// Jump pass else.
|
||||
emitOpcode(compiler, OP_JUMP);
|
||||
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
||||
// Jump pass else.
|
||||
emitOpcode(compiler, OP_JUMP);
|
||||
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
||||
|
||||
patchJump(compiler, ifpatch);
|
||||
compileBlockBody(compiler, BLOCK_ELSE);
|
||||
patchJump(compiler, exit_jump);
|
||||
patchJump(compiler, ifpatch);
|
||||
compileBlockBody(compiler, BLOCK_ELSE);
|
||||
patchJump(compiler, exit_jump);
|
||||
}
|
||||
|
||||
} else {
|
||||
patchJump(compiler, ifpatch);
|
||||
}
|
||||
|
||||
// elsif will not consume the 'end' keyword as it'll be leaved to be consumed
|
||||
// by it's 'if'.
|
||||
if (!elsif) {
|
||||
// 'else if' will not consume the 'end' keyword as it'll be leaved to be
|
||||
// consumed by it's 'if'.
|
||||
if (!else_if) {
|
||||
skipNewLines(compiler);
|
||||
consume(compiler, TK_END, "Expected 'end' after statement end.");
|
||||
}
|
||||
|
@ -51,52 +51,52 @@ def execute(expr)
|
||||
if ptr >= mem.length then list_append(mem, 0) end
|
||||
|
||||
## Decrement the data pointer (to point to the next cell to the left).
|
||||
elsif c == '<'
|
||||
else if c == '<'
|
||||
ptr -= 1
|
||||
if ptr < 0 then assert(false, "ip < 0") end
|
||||
|
||||
## Increment (increase by one) the byte at the data pointer.
|
||||
elsif c == '+'
|
||||
else if c == '+'
|
||||
if mem[ptr] == 255 then mem[ptr] = 0
|
||||
else mem[ptr] += 1 end
|
||||
|
||||
## Decrement (decrease by one) the byte at the data pointer.
|
||||
elsif c == '-'
|
||||
else if c == '-'
|
||||
if mem[ptr] == 0 then mem[ptr] = 255
|
||||
else mem[ptr] -= 1 end
|
||||
|
||||
## output the byte at the data pointer.
|
||||
elsif c == '.'
|
||||
else if c == '.'
|
||||
write(str_chr(mem[ptr]))
|
||||
|
||||
elsif c == ','
|
||||
else if c == ','
|
||||
assert(false, "Currently input isn't supported in pocketlang.")
|
||||
|
||||
## if the byte at the data pointer is zero, then instead of moving the
|
||||
## instruction pointer forward to the next command, jump it forward to
|
||||
## the command after the matching ] command.
|
||||
elsif c == '[' and mem[ptr] == 0
|
||||
else if c == '[' and mem[ptr] == 0
|
||||
open = 0
|
||||
while true
|
||||
i += 1
|
||||
if expr[i] == ']' and open == 0 then break end
|
||||
|
||||
if expr[i] == '[' then open += 1
|
||||
elsif expr[i] == ']' then open -= 1
|
||||
else if expr[i] == ']' then open -= 1
|
||||
end assert(open >= 0)
|
||||
end
|
||||
|
||||
## if the byte at the data pointer is nonzero, then instead of moving the
|
||||
## instruction pointer forward to the next command, jump it back to the
|
||||
## command after the matching [ command
|
||||
elsif c == ']' and mem[ptr] != 0
|
||||
else if c == ']' and mem[ptr] != 0
|
||||
open = 0
|
||||
while true
|
||||
i -= 1
|
||||
if expr[i] == '[' and open == 0 then break end
|
||||
|
||||
if expr[i] == ']' then open -= 1
|
||||
elsif expr[i] == '[' then open += 1
|
||||
else if expr[i] == '[' then open += 1
|
||||
end assert(open <= 0)
|
||||
end
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
for i in 1..100
|
||||
if i%3 == 0 and i%5 == 0 then print('fizzbuzz')
|
||||
elsif i%3 == 0 then print('fizz')
|
||||
elsif i%5 == 0 then print('buzz')
|
||||
else if i%3 == 0 then print('fizz')
|
||||
else if i%5 == 0 then print('buzz')
|
||||
else print(i)
|
||||
end
|
||||
end
|
||||
|
32
tests/examples/matrix.pk
Normal file
32
tests/examples/matrix.pk
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
## Multiply two matrices.
|
||||
|
||||
## A is 3x3 matrix
|
||||
A = [[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]]
|
||||
|
||||
## B is 3x4 matrix.
|
||||
B = [[4, 6, 3, 2],
|
||||
[8, 7, 0, 2],
|
||||
[6, 0, 9, 4]]
|
||||
|
||||
## Result is 3x4 matrix.
|
||||
R = [[0,0,0,0],
|
||||
[0,0,0,0],
|
||||
[0,0,0,0]]
|
||||
|
||||
## Iterate through rows of A.
|
||||
for i in 0..(A.length)
|
||||
## Iterate through columns of B.
|
||||
for j in 0..(B[0].length)
|
||||
for k in 0..(B.length)
|
||||
R[i][j] += A[i][k] * B[k][j]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for row in R
|
||||
print(row)
|
||||
end
|
||||
|
@ -1,19 +0,0 @@
|
||||
|
||||
## Run pocket palette.pk > palette.ppm
|
||||
## Open palatte.ppm with any image viwer which support ppm image
|
||||
## (ex: photoshop, gimp, libre office draw, ...)
|
||||
|
||||
blue = 200
|
||||
|
||||
print("P3")
|
||||
print(255, 255)
|
||||
print(255)
|
||||
|
||||
from lang import write
|
||||
for r in 0..255
|
||||
for g in 0..255
|
||||
write(r, ' ', g, ' ', blue, ' ')
|
||||
end
|
||||
write('\n')
|
||||
end
|
||||
|
@ -18,7 +18,7 @@ assert(0xa1b2c3 == 10597059 and 0xff == 255)
|
||||
assert(0xffffffffffffffff == 18446744073709551615)
|
||||
|
||||
## Lists test.
|
||||
l1 = [1, false, null, func print('hello') end, true]
|
||||
l1 = [1, false, null, function print('hello') end, true]
|
||||
assert(l1[4])
|
||||
l1[3] = null; assert(!l1[3])
|
||||
l1 = [] + [] ; assert(l1.length == 0)
|
||||
@ -45,7 +45,7 @@ assert(math.ceil(1.1) == math.floor(2.9))
|
||||
|
||||
## Logical statement test
|
||||
val = 0; a = false; b = true
|
||||
get_true = func return true end
|
||||
get_true = function 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)
|
||||
|
@ -2,15 +2,15 @@
|
||||
## Simple upvalue.
|
||||
def f1
|
||||
local = "foo"
|
||||
return func
|
||||
return function
|
||||
return local
|
||||
end
|
||||
end
|
||||
assert(f1()() == "foo")
|
||||
|
||||
def add3(x)
|
||||
return func(y)
|
||||
return func(z)
|
||||
return function(y)
|
||||
return function(z)
|
||||
return x + y + z
|
||||
end
|
||||
end
|
||||
@ -21,8 +21,8 @@ assert(add3(7)(6)(4) == 17);
|
||||
## Upvalue external to the inner function.
|
||||
def f2
|
||||
local = "bar"
|
||||
return func
|
||||
fn = func
|
||||
return function
|
||||
fn = function
|
||||
return local
|
||||
end
|
||||
return fn
|
||||
@ -33,10 +33,10 @@ assert(f2()()() == "bar")
|
||||
## Check if upvalues are shared between closures.
|
||||
def f3
|
||||
local = "baz"
|
||||
_fn1 = func(x)
|
||||
_fn1 = function(x)
|
||||
local = x
|
||||
end
|
||||
_fn2 = func
|
||||
_fn2 = function
|
||||
return local
|
||||
end
|
||||
return [_fn1, _fn2]
|
||||
@ -52,7 +52,7 @@ def f4
|
||||
j = i ## 'i' is shared, but 'j' doesn't
|
||||
list_append(
|
||||
a,
|
||||
func
|
||||
function
|
||||
return x + j
|
||||
end
|
||||
)
|
||||
@ -66,13 +66,13 @@ assert(a[1]() == 21)
|
||||
|
||||
def f5
|
||||
l1 = 12
|
||||
return func ## c1
|
||||
return function ## c1
|
||||
l2 = 34
|
||||
return func ## c2
|
||||
return function ## c2
|
||||
l3 = 56
|
||||
return func ## c3
|
||||
return func ## c4
|
||||
return func ## c5
|
||||
return function ## c3
|
||||
return function ## c4
|
||||
return function ## c5
|
||||
return l1 + l2 + l3
|
||||
end
|
||||
end
|
||||
|
@ -1,27 +1,27 @@
|
||||
|
||||
## If statements.
|
||||
variable = null ## Will be changed by the control flow.
|
||||
unreachable = func assert(false, 'Unreachable') end
|
||||
unreachable = function assert(false, 'Unreachable') end
|
||||
|
||||
if true then variable = 42 else unreachable() end
|
||||
assert(variable == 42, 'If statement failed.')
|
||||
|
||||
if false then unreachable()
|
||||
elsif true then variable = null
|
||||
else if true then variable = null
|
||||
else unreachable() end
|
||||
assert(variable == null)
|
||||
|
||||
if false then unreachable()
|
||||
elsif false then unreachable()
|
||||
elsif false then unreachable()
|
||||
else if false then unreachable()
|
||||
else if false then unreachable()
|
||||
else variable = "changed" end
|
||||
assert(variable == "changed")
|
||||
|
||||
if false then unreachable()
|
||||
elsif true
|
||||
else if true
|
||||
if false
|
||||
unreachable()
|
||||
elsif true
|
||||
else if true
|
||||
variable = 123
|
||||
else
|
||||
unreachable()
|
||||
@ -39,9 +39,9 @@ assert(variable == 1212)
|
||||
|
||||
while true
|
||||
variable = 22
|
||||
if true then elsif false then end
|
||||
if true then else if false then end
|
||||
if false
|
||||
elsif true
|
||||
else if true
|
||||
variable += 2300
|
||||
end
|
||||
variable += 1
|
||||
@ -55,6 +55,21 @@ for k in map
|
||||
end
|
||||
assert(sum == 54)
|
||||
|
||||
val = 2
|
||||
if val == 1 then val = null
|
||||
else if val == 2 then val = 'foo'
|
||||
else val = null
|
||||
end
|
||||
assert(val == 'foo')
|
||||
|
||||
val = 2
|
||||
if val == 1 then val = null
|
||||
else
|
||||
if val == 2 then val = 'bar'
|
||||
end ##< Need an extra end since 'else if' != 'else \n if'.
|
||||
end
|
||||
assert(val == 'bar')
|
||||
|
||||
|
||||
# If we got here, that means all test were passed.
|
||||
print('All TESTS PASSED')
|
||||
|
@ -26,7 +26,7 @@ assert([1, 2, 3].length == 3)
|
||||
## Function
|
||||
assert(print.arity == -1)
|
||||
assert(hex.arity == 1)
|
||||
assert(func(a, b)end .arity == 2)
|
||||
assert(function(a, b)end .arity == 2)
|
||||
assert(print.name == "print")
|
||||
def fn(p1, p2, p3) end
|
||||
assert(fn.name == "fn")
|
||||
|
@ -9,7 +9,7 @@ assert(f3('a', 'b', 'c', 'd') == 'c')
|
||||
## Local variables of inner funcions.
|
||||
def f4
|
||||
l1 = 3.14
|
||||
f5 = func
|
||||
f5 = function
|
||||
l2 = 42
|
||||
return l2
|
||||
end
|
||||
|
@ -44,27 +44,27 @@ def eval(expr, ind)
|
||||
end
|
||||
return [val, ind]
|
||||
|
||||
elsif c == '+'
|
||||
else if c == '+'
|
||||
r = binary_op(expr, ind)
|
||||
if not r[0] then return [null, -1] end
|
||||
return [r[1] + r[2], r[3]]
|
||||
|
||||
elsif c == '-'
|
||||
else if c == '-'
|
||||
r = binary_op(expr, ind)
|
||||
if not r[0] then return [null, -1] end
|
||||
return [r[1] - r[2], r[3]]
|
||||
|
||||
elsif c == '*'
|
||||
else if c == '*'
|
||||
r = binary_op(expr, ind)
|
||||
if not r[0] then return [null, -1] end
|
||||
return [r[1] * r[2], r[3]]
|
||||
|
||||
elsif c == '/'
|
||||
else if c == '/'
|
||||
r = binary_op(expr, ind)
|
||||
if not r[0] then return [null, -1] end
|
||||
return [r[1] / r[2], r[3]]
|
||||
|
||||
elsif isnum(c)
|
||||
else if isnum(c)
|
||||
val = str_ord(c) - str_ord('0')
|
||||
assert(0 <= val and val < 10)
|
||||
return [val, ind]
|
||||
|
@ -37,6 +37,7 @@ TEST_SUITE = {
|
||||
"examples/fib.pk",
|
||||
"examples/fizzbuzz.pk",
|
||||
"examples/helloworld.pk",
|
||||
"examples/matrix.pk",
|
||||
"examples/pi.pk",
|
||||
"examples/prime.pk",
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user