Skip to content

Commit

Permalink
add while loop to shiplang
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasballinger committed Feb 14, 2016
1 parent fcfc4ed commit 4b659e0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 2 deletions.
55 changes: 53 additions & 2 deletions eval.ts
@@ -1,4 +1,4 @@
import { ByteCode } from 'interfaces';
type ByteCode = [BC, any];
export enum BC {
LoadConstant,
FunctionLookup,
Expand All @@ -13,6 +13,7 @@ export enum BC {
Store, // arg is variable name, saves TOS
Return, // done with this bytecode
Yield, // done for now, please continue when callback is true
CloneTop, // push on another of the top of the stack
}
interface Scope {
[key: string]: any;
Expand Down Expand Up @@ -149,7 +150,7 @@ class DefineNode extends ASTNode {
return v;
}
tree(){
return 'define\n '+this.value+' to be\n'+indent(this.value.tree(), 1);
return 'define\n '+this.value+' to be\n '+indent(this.value.tree(), 1);
}
compile(){
return [].concat(this.value.compile(), [[BC.StoreNew, this.name]]);
Expand Down Expand Up @@ -248,6 +249,47 @@ class ForeverNode extends ASTNode {
}
}

// while nodes return the first false value the condition evaluates to
class WhileNode extends ASTNode {
constructor(location: Location,
public condition: ASTNode,
public body: ASTNode){
super(location);
}
eval(env: Environment){
while (true){
var a = this.condition.eval(env)
if (!a){ break; }
this.body.eval(env);
}
return a;
}
tree() { return 'while '+this.condition.tree()+'\n' + indent(this.body.tree()); }
compile():ByteCode[]{
//TODO
var condition = this.condition.compile();
var body = this.body.compile();
var popTop = [[BC.Pop, null]];
var goBack = [[BC.Jump, -(1 + // this instruction
1 + // popTop
body.length + popTop.length +
1 + // jumpIfNot
1 + // cloneTop
condition.length)]]
return [].concat(condition,
[[BC.CloneTop, null]],
[[BC.JumpIfNot, (popTop.length +
body.length +
popTop.length +
goBack.length)]],
popTop,
body,
popTop, // discard the result of the body since while loops
// return the falsy condition value
goBack);
}
}

export class CompiledFunctionObject {
constructor(public params: string[], public code: ByteCode[], public env: Environment, public name: string){}
deepCopyCreate():CompiledFunctionObject{
Expand Down Expand Up @@ -398,6 +440,7 @@ parser.nodes.DefineNode = DefineNode;
parser.nodes.YieldNode = YieldNode;
parser.nodes.DefnNode = DefnNode;
parser.nodes.ForeverNode = ForeverNode;
parser.nodes.WhileNode = WhileNode;
parser.nodes.NullNode = NullNode;

export function runBytecodeOneStep(counterStack: number[], bytecodeStack: ByteCode[][],
Expand Down Expand Up @@ -445,6 +488,7 @@ export function runBytecodeOneStep(counterStack: number[], bytecodeStack: ByteCo
stack.push(result);
}
} else {
console.log(func);
if (func.params.length !== arg){
throw Error('Function called with wrong arity! Takes ' +
func.params.length + ' args, given ' + args.length);
Expand Down Expand Up @@ -507,6 +551,9 @@ export function runBytecodeOneStep(counterStack: number[], bytecodeStack: ByteCo
case BC.StoreNew:
env.define(arg, stack[stack.length-1]);
break;
case BC.CloneTop:
stack.push(stack[stack.length-1]);
break;
default:
throw Error('unrecognized bytecode: '+bc+' enumLookup:'+enumLookup(BC, bc));
}
Expand Down Expand Up @@ -554,6 +601,7 @@ var funcs = {
}, 0);
},
'*': function(a:number, b:number){ return a * b; },
'<': function(a:number, b:number){ return a < b; },
}

export function dis(bytecode: ByteCode[], indent=0){
Expand Down Expand Up @@ -693,3 +741,6 @@ function main(){
// (a 1 2)`)
//trace(`(define a (lambda (x y) 1 2 (+ x y)))
// (a 2 3)`);
trace(`(define a 0)
(while (< a 10)
(define a (+ a 1)))`);
4 changes: 4 additions & 0 deletions shiplang.grammar
Expand Up @@ -42,6 +42,7 @@ sexp
/ defnSexp
/ defineSexp
/ foreverSexp
/ whileSexp
/ yieldSexp
/ functionCallSexp
/ atom
Expand All @@ -56,6 +57,9 @@ doSexp
foreverSexp
= "(" _* "forever" _* head:sexp _* rest:(_* sexp)* _* ")" { return new parser.nodes.ForeverNode(location(), doIfMultipleStatements(location(), [head].concat(rest.map(function(x){return x[1];})))); }

whileSexp
= "(" _* "while" _* cond:sexp _* head:sexp _* rest:(_* sexp)* _* ")" { return new parser.nodes.WhileNode(location(), cond, doIfMultipleStatements(location(), [head].concat(rest.map(function(x){return x[1];})))); }

lambdaSexp
= "(" _* "lambda" _* params:functionParams _* head:sexp _* rest:(_* sexp)* _* ")" { return new parser.nodes.LambdaNode(location(), params, doIfMultipleStatements(location(), [head].concat(rest.map(function(x){return x[1];})))); }

Expand Down

0 comments on commit 4b659e0

Please sign in to comment.