diff --git a/example/hello.wren b/example/hello.wren index c4b39389..0cfbf088 100644 --- a/example/hello.wren +++ b/example/hello.wren @@ -1 +1 @@ -123(1, true, "a string".whatevs) +2 diff --git a/src/compiler.c b/src/compiler.c new file mode 100644 index 00000000..9d109324 --- /dev/null +++ b/src/compiler.c @@ -0,0 +1,373 @@ +#include +#include +#include "compiler.h" + +typedef struct +{ + Buffer* source; + Token* current; + + // The block being compiled. + Block* block; + int numCodes; + + // Non-zero if a compile error has occurred. + int hasError; +} Compiler; + +typedef void (*CompileFn)(Compiler*, Token*); + +typedef struct +{ + CompileFn fn; + int precedence; +} InfixCompiler; + +/* +static void block(Compiler* compiler); +*/ +static void statementLike(Compiler* compiler); +static void expression(Compiler* compiler); +static void compilePrecedence(Compiler* compiler, int precedence); +static void prefixLiteral(Compiler* compiler, Token* token); +static void infixCall(Compiler* compiler, Token* token); +static void infixBinaryOp(Compiler* compiler, Token* token); +static TokenType peek(Compiler* compiler); +static Token* match(Compiler* compiler, TokenType expected); +static Token* consume(Compiler* compiler, TokenType expected); +static Token* advance(Compiler* compiler); +static void error(Compiler* compiler, const char* format, ...); + +enum +{ + PREC_NONE, + PREC_LOWEST, + + PREC_EQUALITY, // == != + PREC_COMPARISON, // < > <= >= + PREC_BITWISE, // | & + PREC_TERM, // + - + PREC_FACTOR, // * / % + PREC_CALL // () +}; + +CompileFn prefixCompilers[] = { + NULL, // TOKEN_LEFT_PAREN + NULL, // TOKEN_RIGHT_PAREN + NULL, // TOKEN_LEFT_BRACKET + NULL, // TOKEN_RIGHT_BRACKET + NULL, // TOKEN_LEFT_BRACE + NULL, // TOKEN_RIGHT_BRACE + NULL, // TOKEN_COLON + NULL, // TOKEN_DOT + NULL, // TOKEN_COMMA + NULL, // TOKEN_STAR + NULL, // TOKEN_SLASH + NULL, // TOKEN_PERCENT + NULL, // TOKEN_PLUS + NULL, // TOKEN_MINUS + NULL, // TOKEN_PIPE + NULL, // TOKEN_AMP + NULL, // TOKEN_BANG + NULL, // TOKEN_EQ + NULL, // TOKEN_LT + NULL, // TOKEN_GT + NULL, // TOKEN_LTEQ + NULL, // TOKEN_GTEQ + NULL, // TOKEN_EQEQ + NULL, // TOKEN_BANGEQ + NULL, // TOKEN_ELSE + NULL, // TOKEN_IF + NULL, // TOKEN_VAR + NULL, // TOKEN_EMBEDDED + prefixLiteral, // TOKEN_NAME + prefixLiteral, // TOKEN_NUMBER + prefixLiteral, // TOKEN_STRING + NULL, // TOKEN_LINE + NULL, // TOKEN_WHITESPACE + NULL, // TOKEN_INDENT + NULL, // TOKEN_OUTDENT + NULL, // TOKEN_ERROR + NULL // TOKEN_EOF +}; + +// The indices in this array correspond to TOKEN enum values. +InfixCompiler infixCompilers[] = { + { infixCall, PREC_CALL }, // TOKEN_LEFT_PAREN + { NULL, PREC_NONE }, // TOKEN_RIGHT_PAREN + { NULL, PREC_NONE }, // TOKEN_LEFT_BRACKET + { NULL, PREC_NONE }, // TOKEN_RIGHT_BRACKET + { NULL, PREC_NONE }, // TOKEN_LEFT_BRACE + { NULL, PREC_NONE }, // TOKEN_RIGHT_BRACE + { NULL, PREC_NONE }, // TOKEN_COLON + { NULL, PREC_NONE }, // TOKEN_DOT + { NULL, PREC_NONE }, // TOKEN_COMMA + { infixBinaryOp, PREC_FACTOR }, // TOKEN_STAR + { infixBinaryOp, PREC_FACTOR }, // TOKEN_SLASH + { infixBinaryOp, PREC_FACTOR }, // TOKEN_PERCENT + { infixBinaryOp, PREC_TERM }, // TOKEN_PLUS + { infixBinaryOp, PREC_TERM }, // TOKEN_MINUS + { infixBinaryOp, PREC_BITWISE }, // TOKEN_PIPE + { infixBinaryOp, PREC_BITWISE }, // TOKEN_AMP + { NULL, PREC_NONE }, // TOKEN_BANG + { NULL, PREC_NONE }, // TOKEN_EQ + { infixBinaryOp, PREC_COMPARISON }, // TOKEN_LT + { infixBinaryOp, PREC_COMPARISON }, // TOKEN_GT + { infixBinaryOp, PREC_COMPARISON }, // TOKEN_LTEQ + { infixBinaryOp, PREC_COMPARISON }, // TOKEN_GTEQ + { infixBinaryOp, PREC_EQUALITY }, // TOKEN_EQEQ + { infixBinaryOp, PREC_EQUALITY }, // TOKEN_BANGEQ + { NULL, PREC_NONE }, // TOKEN_ELSE + { NULL, PREC_NONE }, // TOKEN_IF + { NULL, PREC_NONE }, // TOKEN_VAR + { NULL, PREC_NONE }, // TOKEN_EMBEDDED + { NULL, PREC_NONE }, // TOKEN_NAME + { NULL, PREC_NONE }, // TOKEN_NUMBER + { NULL, PREC_NONE }, // TOKEN_STRING + { NULL, PREC_NONE }, // TOKEN_LINE + { NULL, PREC_NONE }, // TOKEN_WHITESPACE + { NULL, PREC_NONE }, // TOKEN_INDENT + { NULL, PREC_NONE }, // TOKEN_OUTDENT + { NULL, PREC_NONE }, // TOKEN_ERROR + { NULL, PREC_NONE } // TOKEN_EOF +}; + +Block* compile(Buffer* source, Token* tokens) +{ + Compiler compiler; + compiler.source = source; + compiler.current = tokens; + compiler.hasError = 0; + + compiler.block = malloc(sizeof(Block)); + // TODO(bob): Hack! make variable sized. + compiler.block->bytecode = malloc(sizeof(Code) * 1024); + + // TODO(bob): Hack! make variable sized. + compiler.block->constants = malloc(sizeof(Value) * 256); + compiler.block->numConstants = 0; + + compiler.numCodes = 0; + + // TODO(bob): Copied from block(). Unify. + do + { + statementLike(&compiler); + } while (!match(&compiler, TOKEN_EOF)); + + compiler.block->bytecode[compiler.numCodes++] = CODE_END; + + return compiler.hasError ? NULL : compiler.block; +} + +/* +static void block(Compiler* compiler) +{ + consume(compiler, TOKEN_INDENT); + + NodeSequence* sequence = malloc(sizeof(NodeSequence)); + sequence->node.type = NODE_SEQUENCE; + sequence->nodes = NULL; + + NodeList** nodes = &sequence->nodes; + do + { + Node* node = statementLike(compiler); + *nodes = malloc(sizeof(NodeList)); + (*nodes)->node = node; + (*nodes)->next = NULL; + nodes = &(*nodes)->next; + + } while (!match(compiler, TOKEN_OUTDENT)); + + return (Node*)sequence; +} +*/ + +static void statementLike(Compiler* compiler) +{ + /* + if (match(compiler, TOKEN_IF)) + { + // Compile the condition. + expression(compiler); + + consume(compiler, TOKEN_COLON); + + // Compile the then arm. + block(compiler); + + // Compile the else arm. + if (match(compiler, TOKEN_ELSE)) + { + consume(compiler, TOKEN_COLON); + block(parser); + } + + return; + } + + if (match(compiler, TOKEN_VAR)) + { + Token* name = consume(compiler, TOKEN_NAME); + Node* initializer = NULL; + if (match(compiler, TOKEN_EQ)) + { + initializer = expression(parser); + } + if (peek(parser) != TOKEN_OUTDENT) consume(compiler, TOKEN_LINE); + + NodeVar* node = malloc(sizeof(NodeVar)); + node->node.type = NODE_VAR; + node->name = name; + node->initializer = initializer; + return (Node*)node; + } + */ + + // Statement expression. + expression(compiler); + consume(compiler, TOKEN_LINE); +} + +static void expression(Compiler* compiler) +{ + compilePrecedence(compiler, PREC_LOWEST); +} + +void compilePrecedence(Compiler* compiler, int precedence) +{ + Token* token = advance(compiler); + CompileFn prefix = prefixCompilers[token->type]; + + if (prefix == NULL) + { + // TODO(bob): Handle error better. + error(compiler, "No prefix parser."); + exit(1); + } + + prefix(compiler, token); + + while (precedence <= infixCompilers[compiler->current->type].precedence) + { + token = advance(compiler); + CompileFn infix = infixCompilers[token->type].fn; + infix(compiler, token); + } +} + +static void prefixLiteral(Compiler* compiler, Token* token) +{ + // TODO(bob): Get actual value from token! + // Define a constant for the literal. + // TODO(bob): See if constant with same value already exists. + Value constant = malloc(sizeof(Obj)); + constant->type = OBJ_INT; + constant->flags = 0; + constant->value = 234; + + compiler->block->constants[compiler->block->numConstants++] = constant; + + // Compile the code to load the constant. + compiler->block->bytecode[compiler->numCodes++] = CODE_CONSTANT; + compiler->block->bytecode[compiler->numCodes++] = compiler->block->numConstants - 1; +} + +static void infixCall(Compiler* compiler, Token* token) +{ + printf("infix calls not implemented\n"); + exit(1); + /* + NodeList* args = NULL; + if (match(compiler, TOKEN_RIGHT_PAREN) == NULL) + { + NodeList** arg = &args; + do + { + *arg = malloc(sizeof(NodeList)); + (*arg)->node = expression(parser); + (*arg)->next = NULL; + arg = &(*arg)->next; + } + while (match(compiler, TOKEN_COMMA) != NULL); + + consume(compiler, TOKEN_RIGHT_PAREN); + } + + NodeCall* node = malloc(sizeof(NodeCall)); + node->node.type = NODE_CALL; + node->fn = left; + node->args = args; + + return (Node*)node; + */ +} + +static void infixBinaryOp(Compiler* compiler, Token* token) +{ + printf("infix binary ops not implemented\n"); + exit(1); + /* + // TODO(bob): Support right-associative infix. Needs to do precedence + // - 1 here to be right-assoc. + Node* right = parsePrecedence(parser, + infixParsers[token->type].precedence); + + NodeBinaryOp* node = malloc(sizeof(NodeBinaryOp)); + node->node.type = NODE_BINARY_OP; + node->left = left; + node->op = token; + node->right = right; + + return (Node*)node; + */ +} + +static TokenType peek(Compiler* compiler) +{ + return compiler->current->type; +} + +static Token* match(Compiler* compiler, TokenType expected) +{ + if (peek(compiler) != expected) return NULL; + + return advance(compiler); +} + +static Token* consume(Compiler* compiler, TokenType expected) +{ + Token* token = advance(compiler); + if (token->type != expected) + { + // TODO(bob): Better error. + error(compiler, "Expected %d, got %d.\n", expected, token->type); + } + + return token; +} + +static Token* advance(Compiler* compiler) +{ + // TODO(bob): Check for EOF. + Token* token = compiler->current; + compiler->current = compiler->current->next; + return unlinkToken(token); +} + +static void error(Compiler* compiler, const char* format, ...) +{ + compiler->hasError = 1; + printf("Compile error on '"); + printToken(compiler->source, compiler->current); + + printf("': "); + + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + + printf("\n"); +} diff --git a/src/compiler.h b/src/compiler.h new file mode 100644 index 00000000..27506c22 --- /dev/null +++ b/src/compiler.h @@ -0,0 +1,9 @@ +#ifndef wren_parser_h +#define wren_parser_h + +#include "lexer.h" +#include "vm.h" + +Block* compile(Buffer* source, Token* tokens); + +#endif diff --git a/src/main.c b/src/main.c index 718af87b..1b15ddd5 100644 --- a/src/main.c +++ b/src/main.c @@ -1,8 +1,9 @@ #include #include +#include "compiler.h" #include "lexer.h" -#include "parser.h" +#include "vm.h" #define MAX_FILE_SIZE 256 * 256 @@ -32,14 +33,13 @@ int main(int argc, const char * argv[]) //printf("Cleaned tokens:\n"); dumpTokens(buffer, tokens); - /*Node* node =*/ parse(buffer, tokens); - - /* - if (defns) generate(buffer, defns); - + Block* block = compile(buffer, tokens); + Fiber* fiber = newFiber(); + Value value = interpret(fiber, block); + printValue(value); + // TODO(bob): Free tokens. // TODO(bob): Free ast. - */ freeBuffer(buffer); @@ -52,8 +52,6 @@ static void dumpTokens(Buffer* buffer, Token* token) { switch (token->type) { - case TOKEN_INDENT: printf("(in)"); break; - case TOKEN_OUTDENT: printf("(out)"); break; case TOKEN_LINE: printf("(line)"); break; case TOKEN_ERROR: printf("(error)"); break; case TOKEN_EOF: printf("(eof)"); break; diff --git a/src/parser.c b/src/parser.c deleted file mode 100644 index c976615d..00000000 --- a/src/parser.c +++ /dev/null @@ -1,349 +0,0 @@ -#include -#include -#include "parser.h" - -typedef struct -{ - Buffer* source; - Token* current; - - // Non-zero if a parse error has occurred. - int hasError; -} Parser; - -typedef Node* (*PrefixParserFn)(Parser*, Token*); -typedef Node* (*InfixParserFn)(Parser*, Node*, Token*); - -typedef struct -{ - InfixParserFn fn; - int precedence; -} InfixParser; - -static Node* block(Parser* parser); -static Node* statementLike(Parser* parser); -static Node* expression(Parser* parser); -static Node* parsePrecedence(Parser* parser, int precedence); -static Node* prefixLiteral(Parser* parser, Token* token); -static Node* infixCall(Parser* parser, Node* left, Token* token); -static Node* infixBinaryOp(Parser* parser, Node* left, Token* token); -static TokenType peek(Parser* parser); -static Token* match(Parser* parser, TokenType expected); -static Token* consume(Parser* parser, TokenType expected); -static Token* advance(Parser* parser); -static void error(Parser* parser, const char* format, ...); - -enum -{ - PREC_NONE, - PREC_LOWEST, - - PREC_EQUALITY, // == != - PREC_COMPARISON, // < > <= >= - PREC_BITWISE, // | & - PREC_TERM, // + - - PREC_FACTOR, // * / % - PREC_CALL // () -}; - -PrefixParserFn prefixParsers[] = { - NULL, // TOKEN_LEFT_PAREN - NULL, // TOKEN_RIGHT_PAREN - NULL, // TOKEN_LEFT_BRACKET - NULL, // TOKEN_RIGHT_BRACKET - NULL, // TOKEN_LEFT_BRACE - NULL, // TOKEN_RIGHT_BRACE - NULL, // TOKEN_COLON - NULL, // TOKEN_DOT - NULL, // TOKEN_COMMA - NULL, // TOKEN_STAR - NULL, // TOKEN_SLASH - NULL, // TOKEN_PERCENT - NULL, // TOKEN_PLUS - NULL, // TOKEN_MINUS - NULL, // TOKEN_PIPE - NULL, // TOKEN_AMP - NULL, // TOKEN_BANG - NULL, // TOKEN_EQ - NULL, // TOKEN_LT - NULL, // TOKEN_GT - NULL, // TOKEN_LTEQ - NULL, // TOKEN_GTEQ - NULL, // TOKEN_EQEQ - NULL, // TOKEN_BANGEQ - NULL, // TOKEN_ELSE - NULL, // TOKEN_IF - NULL, // TOKEN_VAR - NULL, // TOKEN_EMBEDDED - prefixLiteral, // TOKEN_NAME - prefixLiteral, // TOKEN_NUMBER - prefixLiteral, // TOKEN_STRING - NULL, // TOKEN_LINE - NULL, // TOKEN_WHITESPACE - NULL, // TOKEN_INDENT - NULL, // TOKEN_OUTDENT - NULL, // TOKEN_ERROR - NULL // TOKEN_EOF -}; - -// The indices in this array correspond to TOKEN enum values. -InfixParser infixParsers[] = { - { infixCall, PREC_CALL }, // TOKEN_LEFT_PAREN - { NULL, PREC_NONE }, // TOKEN_RIGHT_PAREN - { NULL, PREC_NONE }, // TOKEN_LEFT_BRACKET - { NULL, PREC_NONE }, // TOKEN_RIGHT_BRACKET - { NULL, PREC_NONE }, // TOKEN_LEFT_BRACE - { NULL, PREC_NONE }, // TOKEN_RIGHT_BRACE - { NULL, PREC_NONE }, // TOKEN_COLON - { NULL, PREC_NONE }, // TOKEN_DOT - { NULL, PREC_NONE }, // TOKEN_COMMA - { infixBinaryOp, PREC_FACTOR }, // TOKEN_STAR - { infixBinaryOp, PREC_FACTOR }, // TOKEN_SLASH - { infixBinaryOp, PREC_FACTOR }, // TOKEN_PERCENT - { infixBinaryOp, PREC_TERM }, // TOKEN_PLUS - { infixBinaryOp, PREC_TERM }, // TOKEN_MINUS - { infixBinaryOp, PREC_BITWISE }, // TOKEN_PIPE - { infixBinaryOp, PREC_BITWISE }, // TOKEN_AMP - { NULL, PREC_NONE }, // TOKEN_BANG - { NULL, PREC_NONE }, // TOKEN_EQ - { infixBinaryOp, PREC_COMPARISON }, // TOKEN_LT - { infixBinaryOp, PREC_COMPARISON }, // TOKEN_GT - { infixBinaryOp, PREC_COMPARISON }, // TOKEN_LTEQ - { infixBinaryOp, PREC_COMPARISON }, // TOKEN_GTEQ - { infixBinaryOp, PREC_EQUALITY }, // TOKEN_EQEQ - { infixBinaryOp, PREC_EQUALITY }, // TOKEN_BANGEQ - { NULL, PREC_NONE }, // TOKEN_ELSE - { NULL, PREC_NONE }, // TOKEN_IF - { NULL, PREC_NONE }, // TOKEN_VAR - { NULL, PREC_NONE }, // TOKEN_EMBEDDED - { NULL, PREC_NONE }, // TOKEN_NAME - { NULL, PREC_NONE }, // TOKEN_NUMBER - { NULL, PREC_NONE }, // TOKEN_STRING - { NULL, PREC_NONE }, // TOKEN_LINE - { NULL, PREC_NONE }, // TOKEN_WHITESPACE - { NULL, PREC_NONE }, // TOKEN_INDENT - { NULL, PREC_NONE }, // TOKEN_OUTDENT - { NULL, PREC_NONE }, // TOKEN_ERROR - { NULL, PREC_NONE } // TOKEN_EOF -}; - -Node* parse(Buffer* source, Token* tokens) -{ - Parser parser; - parser.source = source; - parser.current = tokens; - parser.hasError = 0; - - NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence)); - sequence->node.type = NODE_SEQUENCE; - sequence->nodes = NULL; - - // TODO(bob): Copied from block(). Unify. - NodeList** nodes = &sequence->nodes; - do - { - Node* node = statementLike(&parser); - *nodes = (NodeList*)malloc(sizeof(NodeList)); - (*nodes)->node = node; - (*nodes)->next = NULL; - nodes = &(*nodes)->next; - - } while (!match(&parser, TOKEN_EOF)); - - return parser.hasError ? NULL : (Node*)sequence; -} - -static Node* block(Parser* parser) -{ - consume(parser, TOKEN_INDENT); - - NodeSequence* sequence = (NodeSequence*)malloc(sizeof(NodeSequence)); - sequence->node.type = NODE_SEQUENCE; - sequence->nodes = NULL; - - NodeList** nodes = &sequence->nodes; - do - { - Node* node = statementLike(parser); - *nodes = (NodeList*)malloc(sizeof(NodeList)); - (*nodes)->node = node; - (*nodes)->next = NULL; - nodes = &(*nodes)->next; - - } while (!match(parser, TOKEN_OUTDENT)); - - return (Node*)sequence; -} - -static Node* statementLike(Parser* parser) -{ - if (match(parser, TOKEN_IF)) - { - Node* condition = expression(parser); - consume(parser, TOKEN_COLON); - Node* thenArm = block(parser); - Node* elseArm = NULL; - if (match(parser, TOKEN_ELSE)) - { - consume(parser, TOKEN_COLON); - elseArm = block(parser); - } - - NodeIf* expr = (NodeIf*)malloc(sizeof(NodeIf)); - expr->node.type = NODE_IF; - expr->condition = condition; - expr->thenArm = thenArm; - expr->elseArm = elseArm; - return (Node*)expr; - } - - if (match(parser, TOKEN_VAR)) - { - Token* name = consume(parser, TOKEN_NAME); - Node* initializer = NULL; - if (match(parser, TOKEN_EQ)) - { - initializer = expression(parser); - } - if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE); - - NodeVar* node = (NodeVar*)malloc(sizeof(NodeVar)); - node->node.type = NODE_VAR; - node->name = name; - node->initializer = initializer; - return (Node*)node; - } - - // Statement expression. - Node* node = expression(parser); - if (peek(parser) != TOKEN_OUTDENT) consume(parser, TOKEN_LINE); - - return node; -} - -static Node* expression(Parser* parser) -{ - return parsePrecedence(parser, PREC_LOWEST); -} - -Node* parsePrecedence(Parser* parser, int precedence) -{ - Token* token = advance(parser); - PrefixParserFn prefix = prefixParsers[token->type]; - - if (prefix == NULL) - { - // TODO(bob): Handle error better. - error(parser, "No prefix parser."); - exit(1); - } - - Node* left = prefix(parser, token); - - while (precedence <= infixParsers[parser->current->type].precedence) - { - token = advance(parser); - InfixParserFn infix = infixParsers[token->type].fn; - left = infix(parser, left, token); - } - - return left; -} - -static Node* prefixLiteral(Parser* parser, Token* token) -{ - NodeLiteral* node = (NodeLiteral*)malloc(sizeof(NodeLiteral)); - node->node.type = NODE_LITERAL; - node->token = token; - return (Node*)node; -} - -static Node* infixCall(Parser* parser, Node* left, Token* token) -{ - NodeList* args = NULL; - if (match(parser, TOKEN_RIGHT_PAREN) == NULL) - { - NodeList** arg = &args; - do - { - *arg = (NodeList*)malloc(sizeof(NodeList)); - (*arg)->node = expression(parser); - (*arg)->next = NULL; - arg = &(*arg)->next; - } - while (match(parser, TOKEN_COMMA) != NULL); - - consume(parser, TOKEN_RIGHT_PAREN); - } - - NodeCall* node = (NodeCall*)malloc(sizeof(NodeCall)); - node->node.type = NODE_CALL; - node->fn = left; - node->args = args; - - return (Node*)node; -} - -static Node* infixBinaryOp(Parser* parser, Node* left, Token* token) -{ - // TODO(bob): Support right-associative infix. Needs to do precedence - // - 1 here to be right-assoc. - Node* right = parsePrecedence(parser, - infixParsers[token->type].precedence); - - NodeBinaryOp* node = (NodeBinaryOp*)malloc(sizeof(NodeBinaryOp)); - node->node.type = NODE_BINARY_OP; - node->left = left; - node->op = token; - node->right = right; - - return (Node*)node; -} - -static TokenType peek(Parser* parser) -{ - return parser->current->type; -} - -static Token* match(Parser* parser, TokenType expected) -{ - if (peek(parser) != expected) return NULL; - - return advance(parser); -} - -static Token* consume(Parser* parser, TokenType expected) -{ - Token* token = advance(parser); - if (token->type != expected) - { - // TODO(bob): Better error. - error(parser, "Expected %d, got %d.\n", expected, token->type); - } - - return token; -} - -static Token* advance(Parser* parser) -{ - // TODO(bob): Check for EOF. - Token* token = parser->current; - parser->current = parser->current->next; - return unlinkToken(token); -} - -static void error(Parser* parser, const char* format, ...) -{ - parser->hasError = 1; - printf("Parse error on '"); - printToken(parser->source, parser->current); - - printf("': "); - - va_list args; - va_start(args, format); - vprintf(format, args); - va_end(args); - - printf("\n"); -} diff --git a/src/parser.h b/src/parser.h deleted file mode 100644 index e5d28bc1..00000000 --- a/src/parser.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef wren_parser_h -#define wren_parser_h - -#include "lexer.h" - -// AST nodes. - -typedef enum -{ - NODE_LITERAL, - NODE_SEQUENCE, - NODE_CALL, - NODE_BINARY_OP, - NODE_IF, - NODE_VAR, - - NODE_MAX -} NodeType; - -typedef struct -{ - NodeType type; -} Node; - -typedef struct NodeList_s -{ - Node* node; - struct NodeList_s* next; -} NodeList; - -// Numbers, strings, variable names. -typedef struct -{ - Node node; - Token* token; -} NodeLiteral; - -typedef struct -{ - Node node; - NodeList* nodes; -} NodeSequence; - -typedef struct -{ - Node node; - Node* fn; - NodeList* args; -} NodeCall; - -typedef struct -{ - Node node; - Token* op; - Node* left; - Node* right; -} NodeBinaryOp; - -typedef struct -{ - Node node; - Node* condition; - Node* thenArm; - Node* elseArm; -} NodeIf; - -typedef struct -{ - Node node; - Token* name; - Node* initializer; -} NodeVar; - -// Parameters. - -// TODO(bob): Is this needed? -typedef struct -{ - Token* name; -} Param; - -typedef struct ParamList_s -{ - Param* param; - struct ParamList_s* next; -} ParamList; - -Node* parse(Buffer* source, Token* tokens); - -#endif diff --git a/src/token.h b/src/token.h index 4c6ba3c9..aa9b9c7d 100644 --- a/src/token.h +++ b/src/token.h @@ -50,8 +50,6 @@ typedef enum TOKEN_LINE, TOKEN_WHITESPACE, - TOKEN_INDENT, - TOKEN_OUTDENT, TOKEN_ERROR, TOKEN_EOF, diff --git a/src/vm.c b/src/vm.c new file mode 100644 index 00000000..f676bb22 --- /dev/null +++ b/src/vm.c @@ -0,0 +1,49 @@ +#include +#include + +#include "vm.h" + +static Value pop(Fiber* fiber); + +Fiber* newFiber() +{ + Fiber* fiber = (Fiber*)malloc(sizeof(Fiber)); + fiber->stackSize = 0; + + return fiber; +} + +Value interpret(Fiber* fiber, Block* block) +{ + int ip = 0; + for (;;) + { + switch (block->bytecode[ip++]) + { + case CODE_CONSTANT: + { + Value value = block->constants[block->bytecode[ip++]]; + fiber->stack[fiber->stackSize++] = value; + break; + } + + case CODE_END: + return pop(fiber); + } + } +} + +void printValue(Value value) +{ + switch (value->type) + { + case OBJ_INT: + printf("%d", value->value); + break; + } +} + +Value pop(Fiber* fiber) +{ + return fiber->stack[--fiber->stackSize]; +} diff --git a/src/vm.h b/src/vm.h new file mode 100644 index 00000000..942299a4 --- /dev/null +++ b/src/vm.h @@ -0,0 +1,57 @@ +#ifndef wren_vm_h +#define wren_vm_h + +// TODO(bob): Make this externally controllable. +#define STACK_SIZE 1024 + +typedef enum { + OBJ_INT +} ObjType; + +typedef enum +{ + // The object has been marked during the mark phase of GC. + FLAG_MARKED = 0x01, +} ObjFlags; + +typedef struct sObj { + ObjType type; + ObjFlags flags; + + union { + /* OBJ_INT */ + int value; + }; +} Obj; + +typedef Obj* Value; + +typedef struct +{ + Value stack[STACK_SIZE]; + int stackSize; +} Fiber; + +typedef enum +{ + CODE_CONSTANT, + // Load the constant at index [arg]. + + CODE_END + // The current block is done and should be exited. + +} Code; + +typedef struct +{ + unsigned char* bytecode; + Value* constants; + int numConstants; +} Block; + +Fiber* newFiber(); +Value interpret(Fiber* fiber, Block* block); + +void printValue(Value value); + +#endif diff --git a/wren.xcodeproj/project.pbxproj b/wren.xcodeproj/project.pbxproj index cf527490..420135c1 100644 --- a/wren.xcodeproj/project.pbxproj +++ b/wren.xcodeproj/project.pbxproj @@ -9,8 +9,9 @@ /* Begin PBXBuildFile section */ 29AB1F281816E49C004B501E /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F1E1816E49C004B501E /* lexer.c */; }; 29AB1F291816E49C004B501E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F201816E49C004B501E /* main.c */; }; - 29AB1F2A1816E49C004B501E /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F211816E49C004B501E /* parser.c */; }; 29AB1F2C1816E49C004B501E /* token.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F251816E49C004B501E /* token.c */; }; + 29AB1F2F1816FA66004B501E /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F2E1816FA66004B501E /* vm.c */; }; + 29AB1F3218170104004B501E /* compiler.c in Sources */ = {isa = PBXBuildFile; fileRef = 29AB1F3018170104004B501E /* compiler.c */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -30,11 +31,13 @@ 29AB1F1E1816E49C004B501E /* lexer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lexer.c; path = src/lexer.c; sourceTree = SOURCE_ROOT; }; 29AB1F1F1816E49C004B501E /* lexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lexer.h; path = src/lexer.h; sourceTree = SOURCE_ROOT; }; 29AB1F201816E49C004B501E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = src/main.c; sourceTree = SOURCE_ROOT; }; - 29AB1F211816E49C004B501E /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = parser.c; path = src/parser.c; sourceTree = SOURCE_ROOT; }; - 29AB1F221816E49C004B501E /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = parser.h; path = src/parser.h; sourceTree = SOURCE_ROOT; }; 29AB1F251816E49C004B501E /* token.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = token.c; path = src/token.c; sourceTree = SOURCE_ROOT; }; 29AB1F261816E49C004B501E /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = token.h; path = src/token.h; sourceTree = SOURCE_ROOT; }; 29AB1F271816E49C004B501E /* wren.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = wren.1; path = src/wren.1; sourceTree = SOURCE_ROOT; }; + 29AB1F2D1816FA5B004B501E /* vm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vm.h; path = src/vm.h; sourceTree = SOURCE_ROOT; }; + 29AB1F2E1816FA66004B501E /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vm.c; path = src/vm.c; sourceTree = SOURCE_ROOT; }; + 29AB1F3018170104004B501E /* compiler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = compiler.c; path = src/compiler.c; sourceTree = SOURCE_ROOT; }; + 29AB1F3118170104004B501E /* compiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compiler.h; path = src/compiler.h; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -67,13 +70,15 @@ 29AB1F081816E3AD004B501E /* src */ = { isa = PBXGroup; children = ( + 29AB1F3018170104004B501E /* compiler.c */, + 29AB1F3118170104004B501E /* compiler.h */, 29AB1F1E1816E49C004B501E /* lexer.c */, 29AB1F1F1816E49C004B501E /* lexer.h */, 29AB1F201816E49C004B501E /* main.c */, - 29AB1F211816E49C004B501E /* parser.c */, - 29AB1F221816E49C004B501E /* parser.h */, 29AB1F251816E49C004B501E /* token.c */, 29AB1F261816E49C004B501E /* token.h */, + 29AB1F2E1816FA66004B501E /* vm.c */, + 29AB1F2D1816FA5B004B501E /* vm.h */, 29AB1F271816E49C004B501E /* wren.1 */, ); name = src; @@ -132,7 +137,8 @@ buildActionMask = 2147483647; files = ( 29AB1F291816E49C004B501E /* main.c in Sources */, - 29AB1F2A1816E49C004B501E /* parser.c in Sources */, + 29AB1F3218170104004B501E /* compiler.c in Sources */, + 29AB1F2F1816FA66004B501E /* vm.c in Sources */, 29AB1F2C1816E49C004B501E /* token.c in Sources */, 29AB1F281816E49C004B501E /* lexer.c in Sources */, ); @@ -212,6 +218,8 @@ 29AB1F101816E3AD004B501E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_C_LANGUAGE_STANDARD = c89; + GCC_WARN_PEDANTIC = NO; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -219,6 +227,8 @@ 29AB1F111816E3AD004B501E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + GCC_C_LANGUAGE_STANDARD = c89; + GCC_WARN_PEDANTIC = NO; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release;