2021-02-07 15:40:00 +08:00
|
|
|
/*
|
2022-04-03 02:39:57 +08:00
|
|
|
* Copyright (c) 2020-2022 Thakee Nathees
|
|
|
|
* Copyright (c) 2021-2022 Pocketlang Contributors
|
2021-06-09 18:42:26 +08:00
|
|
|
* Distributed Under The MIT License
|
2021-02-07 15:40:00 +08:00
|
|
|
*/
|
|
|
|
|
2021-06-09 18:42:26 +08:00
|
|
|
#include "pk_compiler.h"
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-09 18:42:26 +08:00
|
|
|
#include "pk_core.h"
|
|
|
|
#include "pk_buffers.h"
|
|
|
|
#include "pk_utils.h"
|
|
|
|
#include "pk_vm.h"
|
|
|
|
#include "pk_debug.h"
|
2021-02-18 02:27:24 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// The maximum number of locals or global (if compiling top level module)
|
2021-02-12 01:35:43 +08:00
|
|
|
// to lookup from the compiling context. Also it's limited by it's opcode
|
2021-02-07 15:40:00 +08:00
|
|
|
// which is using a single byte value to identify the local.
|
|
|
|
#define MAX_VARIABLES 256
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// The maximum number of constant literal a module can contain. Also it's
|
2022-04-10 11:07:44 +08:00
|
|
|
// limited by it's opcode which is using a short value to identify.
|
|
|
|
#define MAX_CONSTANTS (1 << 16)
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-04-13 08:34:14 +08:00
|
|
|
// The maximum number of upvaues a literal function can capture from it's
|
|
|
|
// enclosing function.
|
|
|
|
#define MAX_UPVALUES 256
|
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
// The maximum number of names that were used before defined. Its just the size
|
|
|
|
// of the Forward buffer of the compiler. Feel free to increase it if it
|
|
|
|
// require more.
|
|
|
|
#define MAX_FORWARD_NAMES 256
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// Pocketlang support two types of interpolation.
|
|
|
|
//
|
|
|
|
// 1. Name interpolation ex: "Hello $name!"
|
|
|
|
// 2. Expression interpolation ex: "Hello ${getName()}!"
|
|
|
|
//
|
|
|
|
// Consider a string: "a ${ b "c ${d}" } e" -- Here the depth of 'b' is 1 and
|
|
|
|
// the depth of 'd' is 2 and so on. The maximum depth an expression can go is
|
|
|
|
// defined as MAX_STR_INTERP_DEPTH below.
|
|
|
|
#define MAX_STR_INTERP_DEPTH 8
|
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
// The maximum address possible to jump. Similar limitation as above.
|
|
|
|
#define MAX_JUMP (1 << 16)
|
|
|
|
|
|
|
|
// Max number of break statement in a loop statement to patch.
|
|
|
|
#define MAX_BREAK_PATCH 256
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* TOKENS */
|
|
|
|
/*****************************************************************************/
|
2021-06-01 19:50:41 +08:00
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
typedef enum {
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_ERROR = 0,
|
|
|
|
TK_EOF,
|
|
|
|
TK_LINE,
|
|
|
|
|
|
|
|
// symbols
|
|
|
|
TK_DOT, // .
|
|
|
|
TK_DOTDOT, // ..
|
|
|
|
TK_COMMA, // ,
|
|
|
|
TK_COLLON, // :
|
|
|
|
TK_SEMICOLLON, // ;
|
|
|
|
TK_HASH, // #
|
|
|
|
TK_LPARAN, // (
|
|
|
|
TK_RPARAN, // )
|
|
|
|
TK_LBRACKET, // [
|
|
|
|
TK_RBRACKET, // ]
|
|
|
|
TK_LBRACE, // {
|
|
|
|
TK_RBRACE, // }
|
|
|
|
TK_PERCENT, // %
|
|
|
|
|
|
|
|
TK_TILD, // ~
|
|
|
|
TK_AMP, // &
|
|
|
|
TK_PIPE, // |
|
|
|
|
TK_CARET, // ^
|
2021-05-16 15:05:54 +08:00
|
|
|
TK_ARROW, // ->
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
TK_PLUS, // +
|
|
|
|
TK_MINUS, // -
|
|
|
|
TK_STAR, // *
|
|
|
|
TK_FSLASH, // /
|
2022-05-08 18:02:51 +08:00
|
|
|
TK_STARSTAR, // **
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_BSLASH, // \.
|
|
|
|
TK_EQ, // =
|
|
|
|
TK_GT, // >
|
|
|
|
TK_LT, // <
|
|
|
|
|
|
|
|
TK_EQEQ, // ==
|
|
|
|
TK_NOTEQ, // !=
|
|
|
|
TK_GTEQ, // >=
|
|
|
|
TK_LTEQ, // <=
|
|
|
|
|
|
|
|
TK_PLUSEQ, // +=
|
|
|
|
TK_MINUSEQ, // -=
|
|
|
|
TK_STAREQ, // *=
|
|
|
|
TK_DIVEQ, // /=
|
2021-06-22 20:19:52 +08:00
|
|
|
TK_MODEQ, // %=
|
2022-05-08 18:02:51 +08:00
|
|
|
TK_POWEQ, // **=
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2021-06-15 00:20:07 +08:00
|
|
|
TK_ANDEQ, // &=
|
2021-06-15 12:36:10 +08:00
|
|
|
TK_OREQ, // |=
|
|
|
|
TK_XOREQ, // ^=
|
2021-06-15 00:20:07 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_SRIGHT, // >>
|
|
|
|
TK_SLEFT, // <<
|
|
|
|
|
2021-06-23 22:24:20 +08:00
|
|
|
TK_SRIGHTEQ, // >>=
|
|
|
|
TK_SLEFTEQ, // <<=
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
// Keywords.
|
2021-06-20 23:28:31 +08:00
|
|
|
TK_CLASS, // class
|
2021-05-10 03:00:59 +08:00
|
|
|
TK_FROM, // from
|
2021-05-06 22:19:30 +08:00
|
|
|
TK_IMPORT, // import
|
2021-05-09 20:31:36 +08:00
|
|
|
TK_AS, // as
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_DEF, // def
|
2021-05-11 14:38:23 +08:00
|
|
|
TK_NATIVE, // native (C function declaration)
|
2022-05-07 13:48:06 +08:00
|
|
|
TK_FN, // function (literal function)
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_END, // end
|
|
|
|
|
|
|
|
TK_NULL, // null
|
|
|
|
TK_IN, // in
|
2022-04-27 00:27:35 +08:00
|
|
|
TK_IS, // is
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_AND, // and
|
|
|
|
TK_OR, // or
|
2021-02-17 02:28:03 +08:00
|
|
|
TK_NOT, // not / !
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_TRUE, // true
|
|
|
|
TK_FALSE, // false
|
2022-04-21 19:53:03 +08:00
|
|
|
TK_SELF, // self
|
2022-05-01 21:12:13 +08:00
|
|
|
TK_SUPER, // super
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
TK_DO, // do
|
2021-05-11 14:38:23 +08:00
|
|
|
TK_THEN, // then
|
2021-02-12 01:35:43 +08:00
|
|
|
TK_WHILE, // while
|
|
|
|
TK_FOR, // for
|
|
|
|
TK_IF, // if
|
|
|
|
TK_ELSE, // else
|
|
|
|
TK_BREAK, // break
|
|
|
|
TK_CONTINUE, // continue
|
|
|
|
TK_RETURN, // return
|
|
|
|
|
|
|
|
TK_NAME, // identifier
|
|
|
|
|
|
|
|
TK_NUMBER, // number literal
|
|
|
|
TK_STRING, // string literal
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
/* String interpolation
|
2022-04-05 12:26:48 +08:00
|
|
|
* "a ${b} c $d e"
|
2021-02-12 01:35:43 +08:00
|
|
|
* tokenized as:
|
|
|
|
* TK_STR_INTERP "a "
|
|
|
|
* TK_NAME b
|
|
|
|
* TK_STR_INTERP " c "
|
|
|
|
* TK_NAME d
|
|
|
|
* TK_STRING " e" */
|
2022-04-05 10:55:32 +08:00
|
|
|
TK_STRING_INTERP,
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
} TokenType;
|
|
|
|
|
|
|
|
typedef struct {
|
2021-02-12 01:35:43 +08:00
|
|
|
TokenType type;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
const char* start; //< Begining of the token in the source.
|
|
|
|
int length; //< Number of chars of the token.
|
|
|
|
int line; //< Line number of the token (1 based).
|
|
|
|
Var value; //< Literal value of the token.
|
2021-02-07 15:40:00 +08:00
|
|
|
} Token;
|
|
|
|
|
|
|
|
typedef struct {
|
2021-02-12 01:35:43 +08:00
|
|
|
const char* identifier;
|
|
|
|
int length;
|
|
|
|
TokenType tk_type;
|
2021-02-07 15:40:00 +08:00
|
|
|
} _Keyword;
|
|
|
|
|
|
|
|
// List of keywords mapped into their identifiers.
|
|
|
|
static _Keyword _keywords[] = {
|
2021-06-20 23:28:31 +08:00
|
|
|
{ "class", 5, TK_CLASS },
|
2021-06-01 19:50:41 +08:00
|
|
|
{ "from", 4, TK_FROM },
|
|
|
|
{ "import", 6, TK_IMPORT },
|
|
|
|
{ "as", 2, TK_AS },
|
|
|
|
{ "def", 3, TK_DEF },
|
|
|
|
{ "native", 6, TK_NATIVE },
|
2022-05-07 13:48:06 +08:00
|
|
|
{ "fn", 2, TK_FN },
|
2021-06-01 19:50:41 +08:00
|
|
|
{ "end", 3, TK_END },
|
|
|
|
{ "null", 4, TK_NULL },
|
|
|
|
{ "in", 2, TK_IN },
|
2022-04-27 00:27:35 +08:00
|
|
|
{ "is", 2, TK_IS },
|
2021-06-01 19:50:41 +08:00
|
|
|
{ "and", 3, TK_AND },
|
|
|
|
{ "or", 2, TK_OR },
|
|
|
|
{ "not", 3, TK_NOT },
|
|
|
|
{ "true", 4, TK_TRUE },
|
|
|
|
{ "false", 5, TK_FALSE },
|
2022-04-21 19:53:03 +08:00
|
|
|
{ "self", 4, TK_SELF },
|
2022-05-01 21:12:13 +08:00
|
|
|
{ "super", 5, TK_SUPER },
|
2021-06-01 19:50:41 +08:00
|
|
|
{ "do", 2, TK_DO },
|
|
|
|
{ "then", 4, TK_THEN },
|
|
|
|
{ "while", 5, TK_WHILE },
|
|
|
|
{ "for", 3, TK_FOR },
|
|
|
|
{ "if", 2, TK_IF },
|
|
|
|
{ "else", 4, TK_ELSE },
|
|
|
|
{ "break", 5, TK_BREAK },
|
2021-02-12 01:35:43 +08:00
|
|
|
{ "continue", 8, TK_CONTINUE },
|
2021-06-01 19:50:41 +08:00
|
|
|
{ "return", 6, TK_RETURN },
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-03-31 02:13:18 +08:00
|
|
|
{ NULL, 0, (TokenType)(0) }, // Sentinel to mark the end of the array.
|
2021-02-07 15:40:00 +08:00
|
|
|
};
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* COMPILER INTERNAL TYPES */
|
|
|
|
/*****************************************************************************/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
// Precedence parsing references:
|
2021-06-01 19:50:41 +08:00
|
|
|
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
typedef enum {
|
2021-02-12 01:35:43 +08:00
|
|
|
PREC_NONE,
|
|
|
|
PREC_LOWEST,
|
|
|
|
PREC_LOGICAL_OR, // or
|
|
|
|
PREC_LOGICAL_AND, // and
|
|
|
|
PREC_EQUALITY, // == !=
|
2021-06-23 18:21:59 +08:00
|
|
|
PREC_TEST, // in is
|
2021-02-12 01:35:43 +08:00
|
|
|
PREC_COMPARISION, // < > <= >=
|
|
|
|
PREC_BITWISE_OR, // |
|
|
|
|
PREC_BITWISE_XOR, // ^
|
|
|
|
PREC_BITWISE_AND, // &
|
|
|
|
PREC_BITWISE_SHIFT, // << >>
|
|
|
|
PREC_RANGE, // ..
|
|
|
|
PREC_TERM, // + -
|
|
|
|
PREC_FACTOR, // * / %
|
2021-06-23 18:21:59 +08:00
|
|
|
PREC_UNARY, // - ! ~ not
|
2022-05-08 18:02:51 +08:00
|
|
|
PREC_EXPONENT, // **
|
2021-02-12 01:35:43 +08:00
|
|
|
PREC_CALL, // ()
|
|
|
|
PREC_SUBSCRIPT, // []
|
|
|
|
PREC_ATTRIB, // .index
|
|
|
|
PREC_PRIMARY,
|
2021-02-07 15:40:00 +08:00
|
|
|
} Precedence;
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
typedef void (*GrammarFn)(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
typedef struct {
|
2021-02-12 01:35:43 +08:00
|
|
|
GrammarFn prefix;
|
|
|
|
GrammarFn infix;
|
|
|
|
Precedence precedence;
|
2021-02-07 15:40:00 +08:00
|
|
|
} GrammarRule;
|
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
typedef enum {
|
|
|
|
DEPTH_GLOBAL = -1, //< Global variables.
|
|
|
|
DEPTH_LOCAL, //< Local scope. Increase with inner scope.
|
|
|
|
} Depth;
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
typedef enum {
|
|
|
|
FUNC_MAIN, // The body function of the script.
|
|
|
|
FUNC_TOPLEVEL,
|
|
|
|
FUNC_LITERAL,
|
|
|
|
FUNC_METHOD,
|
|
|
|
FUNC_CONSTRUCTOR,
|
|
|
|
} FuncType;
|
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
typedef struct {
|
2021-02-12 01:35:43 +08:00
|
|
|
const char* name; //< Directly points into the source string.
|
2021-06-08 00:56:56 +08:00
|
|
|
uint32_t length; //< Length of the name.
|
2021-02-13 21:57:59 +08:00
|
|
|
int depth; //< The depth the local is defined in.
|
2022-04-13 08:34:14 +08:00
|
|
|
bool is_upvalue; //< Is this an upvalue for a nested function.
|
2021-02-12 01:35:43 +08:00
|
|
|
int line; //< The line variable declared for debugging.
|
2021-06-04 22:55:06 +08:00
|
|
|
} Local;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
typedef struct sLoop {
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Index of the loop's start instruction where the execution will jump
|
|
|
|
// back to once it reach the loop end or continue used.
|
|
|
|
int start;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Index of the jump out address instruction to patch it's value once done
|
|
|
|
// compiling the loop.
|
|
|
|
int exit_jump;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Array of address indexes to patch break address.
|
|
|
|
int patches[MAX_BREAK_PATCH];
|
|
|
|
int patch_count;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// The outer loop of the current loop used to set and reset the compiler's
|
|
|
|
// current loop context.
|
|
|
|
struct sLoop* outer_loop;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-05-13 17:10:57 +08:00
|
|
|
// Depth of the loop, required to pop all the locals in that loop when it
|
|
|
|
// met a break/continue statement inside.
|
|
|
|
int depth;
|
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
} Loop;
|
|
|
|
|
2022-04-10 11:07:44 +08:00
|
|
|
// ForwardName is used for globals that are accessed before defined inside
|
|
|
|
// a local scope.
|
|
|
|
// TODO: Since function and class global variables are initialized at the
|
|
|
|
// compile time we can allow access to them at the global scope.
|
2021-05-20 22:05:57 +08:00
|
|
|
typedef struct sForwardName {
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Index of the short instruction that has the value of the global's name
|
|
|
|
// (in the names buffer of the module).
|
2021-05-20 22:05:57 +08:00
|
|
|
int instruction;
|
|
|
|
|
|
|
|
// The function where the name is used, and the instruction is belongs to.
|
|
|
|
Fn* func;
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
// Name token that was lexed for this name.
|
|
|
|
Token tkname;
|
2021-05-20 22:05:57 +08:00
|
|
|
|
|
|
|
} ForwardName;
|
|
|
|
|
2022-04-13 08:34:14 +08:00
|
|
|
// This struct is used to keep track about the information of the upvaues for
|
|
|
|
// the current function to generate opcodes to capture them.
|
|
|
|
typedef struct sUpvalueInfo {
|
|
|
|
|
|
|
|
// If it's true the extrenal local belongs to the immediate enclosing
|
|
|
|
// function and the bellow [index] refering at the locals of that function.
|
|
|
|
// If it's false the external local of the upvalue doesn't belongs to the
|
|
|
|
// immediate enclosing function and the [index] will refering to the upvalues
|
|
|
|
// array of the enclosing function.
|
|
|
|
bool is_immediate;
|
|
|
|
|
|
|
|
// Index of the upvalue's external local variable, in the local or upvalues
|
|
|
|
// array of the enclosing function.
|
|
|
|
int index;
|
|
|
|
|
|
|
|
} UpvalueInfo;
|
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
typedef struct sFunc {
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
// Type of the current function.
|
|
|
|
FuncType type;
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Scope of the function. -2 for module body function, -1 for top level
|
|
|
|
// function and literal functions will have the scope where it declared.
|
2021-02-13 21:57:59 +08:00
|
|
|
int depth;
|
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
Local locals[MAX_VARIABLES]; //< Variables in the current context.
|
|
|
|
int local_count; //< Number of locals in [locals].
|
|
|
|
|
2022-04-13 08:34:14 +08:00
|
|
|
UpvalueInfo upvalues[MAX_UPVALUES]; //< Upvalues in the current context.
|
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
int stack_size; //< Current size including locals ind temps.
|
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
// The actual function pointer which is being compiled.
|
|
|
|
Function* ptr;
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// If outer function of this function, for top level function the outer
|
|
|
|
// function will be the module's body function.
|
2021-02-13 21:57:59 +08:00
|
|
|
struct sFunc* outer_func;
|
|
|
|
|
|
|
|
} Func;
|
|
|
|
|
2021-06-15 15:37:49 +08:00
|
|
|
// A convenient macro to get the current function.
|
2021-02-13 21:57:59 +08:00
|
|
|
#define _FN (compiler->func->ptr->fn)
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// The context of the parsing phase for the compiler.
|
|
|
|
typedef struct sParser {
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// Parser need a reference of the PKVM to allocate strings (for string
|
|
|
|
// literals in the source) and to report error if there is any.
|
2021-05-09 18:28:00 +08:00
|
|
|
PKVM* vm;
|
2021-05-18 19:21:38 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// The [source] and the [file_path] are pointers to an allocated string.
|
|
|
|
// The parser doesn't keep references to that objects (to prevent them
|
|
|
|
// from garbage collected). It's the compiler's responsibility to keep the
|
|
|
|
// strings alive alive as long as the parser is alive.
|
|
|
|
|
|
|
|
const char* source; //< Currently compiled source.
|
|
|
|
const char* file_path; //< Path of the module (for reporting errors).
|
2021-05-18 19:21:38 +08:00
|
|
|
const char* token_start; //< Start of the currently parsed token.
|
|
|
|
const char* current_char; //< Current char position in the source.
|
|
|
|
int current_line; //< Line number of the current char.
|
|
|
|
Token previous, current, next; //< Currently parsed tokens.
|
2021-06-09 18:42:26 +08:00
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// The current depth of the string interpolation. 0 means we're not inside
|
|
|
|
// an interpolated string.
|
|
|
|
int si_depth;
|
|
|
|
|
|
|
|
// If we're parsing an interpolated string and found a TK_RBRACE (ie. '}')
|
|
|
|
// we need to know if that's belongs to the expression we're parsing, or the
|
|
|
|
// end of the current interpolation.
|
|
|
|
//
|
|
|
|
// To achieve that We need to keep track of the number of open brace at the
|
|
|
|
// current depth. If we don't have any open brace then the TK_RBRACE token
|
|
|
|
// is consumed to end the interpolation.
|
|
|
|
//
|
|
|
|
// If we're inside an interpolated string (ie. si_depth > 0)
|
|
|
|
// si_open_brace[si_depth - 1] will return the number of open brace at the
|
|
|
|
// current depth.
|
|
|
|
int si_open_brace[MAX_STR_INTERP_DEPTH];
|
|
|
|
|
|
|
|
// Since we're supporting both quotes (single and double), we need to keep
|
|
|
|
// track of the qoute the interpolation is surrounded by to properly
|
|
|
|
// terminate the string.
|
|
|
|
// here si_quote[si_depth - 1] will return the surrunded quote of the
|
|
|
|
// expression at current depth.
|
|
|
|
char si_quote[MAX_STR_INTERP_DEPTH];
|
|
|
|
|
2022-04-05 12:26:48 +08:00
|
|
|
// When we're parsing a name interpolated string (ie. "Hello $name!") we
|
|
|
|
// have to keep track of where the name ends to start the interpolation
|
|
|
|
// from there. The below value [si_name_end] will be NULL if we're not
|
|
|
|
// parsing a name interpolated string, otherwise it'll points to the end of
|
|
|
|
// the name.
|
|
|
|
//
|
|
|
|
// Also we're using [si_name_quote] to store the quote of the string to
|
|
|
|
// properly terminate.
|
|
|
|
const char* si_name_end;
|
|
|
|
char si_name_quote;
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// An array of implicitly forward declared names, which will be resolved once
|
2022-04-11 16:04:22 +08:00
|
|
|
// the module is completely compiled.
|
2022-04-07 11:28:51 +08:00
|
|
|
ForwardName forwards[MAX_FORWARD_NAMES];
|
|
|
|
int forwards_count;
|
|
|
|
|
2022-05-07 13:48:06 +08:00
|
|
|
// A syntax sugar to skip call parentheses. Like lua support for number of
|
|
|
|
// literals. We're doing it for literal functions for now. It'll be set to
|
|
|
|
// true before exprCall to indicate that the call paran should be skipped.
|
|
|
|
bool optional_call_paran;
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
bool repl_mode;
|
|
|
|
bool parsing_class;
|
2022-04-05 12:26:48 +08:00
|
|
|
bool need_more_lines; //< True if we need more lines in REPL mode.
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
// [has_errors] is for all kinds of errors, If it's set we don't terminate
|
|
|
|
// the compilation since we can cascade more errors by continuing. But
|
|
|
|
// [has_syntax_error] will set to true if we encounter one and this will
|
|
|
|
// terminatie the compilation.
|
|
|
|
bool has_syntax_error;
|
|
|
|
bool has_errors;
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
} Parser;
|
|
|
|
|
|
|
|
struct Compiler {
|
|
|
|
|
|
|
|
// The parser of the compiler which contains all the parsing context for the
|
|
|
|
// current compilation.
|
|
|
|
Parser parser;
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Each module will be compiled with it's own compiler and a module is
|
|
|
|
// imported, a new compiler is created for that module and it'll be added to
|
|
|
|
// the linked list of compilers at the begining. PKVM will use this compiler
|
|
|
|
// reference as a root object (objects which won't garbage collected) and
|
|
|
|
// the chain of compilers will be marked at the marking phase.
|
2022-04-07 11:28:51 +08:00
|
|
|
//
|
|
|
|
// Here is how the chain change when a new compiler (compiler_3) created.
|
|
|
|
//
|
|
|
|
// PKVM -> compiler_2 -> compiler_1 -> NULL
|
|
|
|
//
|
|
|
|
// PKVM -> compiler_3 -> compiler_2 -> compiler_1 -> NULL
|
|
|
|
//
|
|
|
|
Compiler* next_compiler;
|
|
|
|
|
2022-05-04 14:28:23 +08:00
|
|
|
const CompileOptions* options; //< To configure the compilation.
|
2021-06-07 13:54:06 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
Module* module; //< Current module that's being compiled.
|
|
|
|
Loop* loop; //< Current loop the we're parsing.
|
|
|
|
Func* func; //< Current function we're parsing.
|
2022-04-07 11:28:51 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Current depth the compiler in (-1 means top level) 0 means function
|
|
|
|
// level and > 0 is inner scope.
|
|
|
|
int scope_depth;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-25 17:03:06 +08:00
|
|
|
// True if the last statement is a new local variable assignment. Because
|
2021-06-15 15:37:49 +08:00
|
|
|
// the assignment is different than regular assignment and use this boolean
|
2021-02-25 17:03:06 +08:00
|
|
|
// to tell the compiler that dont pop it's assigned value because the value
|
|
|
|
// itself is the local.
|
|
|
|
bool new_local;
|
2021-06-04 22:55:06 +08:00
|
|
|
|
|
|
|
// Will be true when parsing an "l-value" which can be assigned to a value
|
|
|
|
// using the assignment operator ('='). ie. 'a = 42' here a is an "l-value"
|
|
|
|
// and the 42 is a "r-value" so the assignment is consumed and compiled.
|
|
|
|
// Consider '42 = a' where 42 is a "r-value" which cannot be assigned.
|
2021-06-15 15:37:49 +08:00
|
|
|
// Similarly 'a = 1 + b = 2' the expression '(1 + b)' is a "r value" and
|
2021-06-04 22:55:06 +08:00
|
|
|
// the assignment here is invalid, however 'a = 1 + (b = 2)' is valid because
|
|
|
|
// the 'b' is an "l-value" and can be assigned but the '(b = 2)' is a
|
|
|
|
// "r-value".
|
|
|
|
bool l_value;
|
2021-06-13 04:17:44 +08:00
|
|
|
|
2022-04-04 23:07:29 +08:00
|
|
|
// This value will be true after parsing a call expression, for every other
|
|
|
|
// Expressions it'll be false. This is **ONLY** to be used when compiling a
|
|
|
|
// return statement to check if the last parsed expression is a call to
|
|
|
|
// perform a tail call optimization (anywhere else this below boolean is
|
|
|
|
// meaningless).
|
2021-06-13 04:17:44 +08:00
|
|
|
bool is_last_call;
|
2022-04-05 10:55:32 +08:00
|
|
|
|
|
|
|
// Since the compiler manually call some builtin functions we need to cache
|
|
|
|
// the index of the functions in order to prevent search for them each time.
|
|
|
|
int bifn_list_join;
|
2021-02-09 16:21:10 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct {
|
2021-02-12 01:35:43 +08:00
|
|
|
int params;
|
|
|
|
int stack;
|
2021-02-09 16:21:10 +08:00
|
|
|
} OpInfo;
|
|
|
|
|
|
|
|
static OpInfo opcode_info[] = {
|
2021-02-12 01:35:43 +08:00
|
|
|
#define OPCODE(name, params, stack) { params, stack },
|
2021-06-09 18:42:26 +08:00
|
|
|
#include "pk_opcodes.h"
|
2021-02-12 01:35:43 +08:00
|
|
|
#undef OPCODE
|
2021-02-07 15:40:00 +08:00
|
|
|
};
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* INITALIZATION FUNCTIONS */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
2022-04-12 04:49:09 +08:00
|
|
|
// FIXME:
|
|
|
|
// This forward declaration can be removed once the interpolated string's
|
|
|
|
// "list_join" function replaced with BUILD_STRING opcode. (The declaration
|
|
|
|
// needed at compiler initialization function to find the "list_join" function.
|
|
|
|
static int findBuiltinFunction(const PKVM* vm,
|
|
|
|
const char* name, uint32_t length);
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// This should be called once the compiler initialized (to access it's fields).
|
|
|
|
static void parserInit(Parser* parser, PKVM* vm, Compiler* compiler,
|
|
|
|
const char* source, const char* path) {
|
|
|
|
|
|
|
|
parser->vm = vm;
|
|
|
|
|
|
|
|
parser->source = source;
|
|
|
|
parser->file_path = path;
|
|
|
|
parser->token_start = parser->source;
|
|
|
|
parser->current_char = parser->source;
|
|
|
|
parser->current_line = 1;
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
parser->previous.type = TK_ERROR;
|
|
|
|
parser->current.type = TK_ERROR;
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->next.type = TK_ERROR;
|
2022-04-22 20:21:17 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->next.start = NULL;
|
|
|
|
parser->next.length = 0;
|
|
|
|
parser->next.line = 1;
|
|
|
|
parser->next.value = VAR_UNDEFINED;
|
|
|
|
|
|
|
|
parser->si_depth = 0;
|
|
|
|
parser->si_name_end = NULL;
|
|
|
|
parser->si_name_quote = '\0';
|
|
|
|
|
|
|
|
parser->forwards_count = 0;
|
|
|
|
|
|
|
|
parser->repl_mode = !!(compiler->options && compiler->options->repl_mode);
|
2022-05-07 13:48:06 +08:00
|
|
|
parser->optional_call_paran = false;
|
2022-04-21 19:53:03 +08:00
|
|
|
parser->parsing_class = false;
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->has_errors = false;
|
2022-04-22 20:21:17 +08:00
|
|
|
parser->has_syntax_error = false;
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->need_more_lines = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void compilerInit(Compiler* compiler, PKVM* vm, const char* source,
|
2022-05-04 14:28:23 +08:00
|
|
|
Module* module, const CompileOptions* options) {
|
2022-04-07 11:28:51 +08:00
|
|
|
|
|
|
|
compiler->next_compiler = NULL;
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
compiler->module = module;
|
2022-04-07 11:28:51 +08:00
|
|
|
compiler->options = options;
|
|
|
|
|
|
|
|
compiler->scope_depth = DEPTH_GLOBAL;
|
|
|
|
|
|
|
|
compiler->loop = NULL;
|
|
|
|
compiler->func = NULL;
|
|
|
|
|
|
|
|
compiler->new_local = false;
|
|
|
|
compiler->is_last_call = false;
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
const char* source_path = "@??";
|
|
|
|
if (module->path != NULL) {
|
|
|
|
source_path = module->path->data;
|
|
|
|
} else if (options->repl_mode) {
|
|
|
|
source_path = "@REPL";
|
|
|
|
}
|
|
|
|
|
|
|
|
parserInit(&compiler->parser, vm, compiler, source, source_path);
|
2022-04-07 11:28:51 +08:00
|
|
|
|
|
|
|
// Cache the required built functions.
|
|
|
|
compiler->bifn_list_join = findBuiltinFunction(vm, "list_join", 9);
|
|
|
|
ASSERT(compiler->bifn_list_join >= 0, OOPS);
|
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* ERROR HANDLERS */
|
|
|
|
/*****************************************************************************/
|
2021-02-08 02:30:29 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
// Internal error report function for lexing and parsing.
|
2022-04-22 20:21:17 +08:00
|
|
|
static void reportError(Parser* parser, Token tk,
|
2021-02-08 02:30:29 +08:00
|
|
|
const char* fmt, va_list args) {
|
2021-06-09 18:42:26 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->has_errors = true;
|
2021-06-09 18:42:26 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
PKVM* vm = parser->vm;
|
|
|
|
if (vm->config.stderr_write == NULL) return;
|
|
|
|
|
2021-06-15 15:37:49 +08:00
|
|
|
// If the source is incomplete we're not printing an error message,
|
2021-06-09 18:42:26 +08:00
|
|
|
// instead return PK_RESULT_UNEXPECTED_EOF to the host.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->need_more_lines) {
|
|
|
|
ASSERT(parser->repl_mode, OOPS);
|
2021-06-09 18:42:26 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
reportCompileTimeError(vm, parser->file_path, tk.line, parser->source,
|
|
|
|
tk.start, tk.length, fmt, args);
|
2021-06-04 22:55:06 +08:00
|
|
|
|
2021-02-08 02:30:29 +08:00
|
|
|
}
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
// Error caused when parsing. The associated token assumed to be last consumed
|
|
|
|
// which is [parser->previous].
|
|
|
|
static void syntaxError(Compiler* compiler, Token tk, const char* fmt, ...) {
|
|
|
|
Parser* parser = &compiler->parser;
|
|
|
|
|
|
|
|
// Only one syntax error is reported.
|
|
|
|
if (parser->has_syntax_error) return;
|
|
|
|
|
|
|
|
parser->has_syntax_error = true;
|
2021-02-12 01:35:43 +08:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2022-04-22 20:21:17 +08:00
|
|
|
reportError(parser, tk, fmt, args);
|
2021-02-12 01:35:43 +08:00
|
|
|
va_end(args);
|
2021-02-08 02:30:29 +08:00
|
|
|
}
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
static void semanticError(Compiler* compiler, Token tk, const char* fmt, ...) {
|
|
|
|
Parser* parser = &compiler->parser;
|
2021-02-08 02:30:29 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
// If the parser has synax errors, semantic errors are not reported.
|
|
|
|
if (parser->has_syntax_error) return;
|
2021-02-08 02:30:29 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2022-04-22 20:21:17 +08:00
|
|
|
reportError(parser, tk, fmt, args);
|
2021-02-12 01:35:43 +08:00
|
|
|
va_end(args);
|
2021-02-08 02:30:29 +08:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
// Error caused when trying to resolve forward names (maybe more in the
|
2022-04-11 16:04:22 +08:00
|
|
|
// future), Which will be called once after compiling the module and thus we
|
2021-06-15 15:37:49 +08:00
|
|
|
// need to pass the line number the error originated from.
|
2022-04-22 20:21:17 +08:00
|
|
|
static void resolveError(Compiler* compiler, Token tk, const char* fmt, ...) {
|
|
|
|
Parser* parser = &compiler->parser;
|
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2022-04-22 20:21:17 +08:00
|
|
|
reportError(parser, tk, fmt, args);
|
2021-05-20 22:05:57 +08:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2022-04-15 12:19:47 +08:00
|
|
|
// Check if the given [index] is greater than or equal to the maximum constants
|
|
|
|
// that a module can contain and report an error.
|
|
|
|
static void checkMaxConstantsReached(Compiler* compiler, int index) {
|
|
|
|
ASSERT(index >= 0, OOPS);
|
|
|
|
if (index >= MAX_CONSTANTS) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"A module should contain at most %d unique constants.", MAX_CONSTANTS);
|
2022-04-15 12:19:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* LEXING */
|
|
|
|
/*****************************************************************************/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
// Forward declaration of lexer methods.
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
static Token makeErrToken(Parser* parser);
|
2022-04-07 11:28:51 +08:00
|
|
|
static char peekChar(Parser* parser);
|
|
|
|
static char peekNextChar(Parser* parser);
|
|
|
|
static char eatChar(Parser* parser);
|
|
|
|
static void setNextValueToken(Parser* parser, TokenType type, Var value);
|
|
|
|
static void setNextToken(Parser* parser, TokenType type);
|
|
|
|
static bool matchChar(Parser* parser, char c);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
static void eatString(Compiler* compiler, bool single_quote) {
|
|
|
|
Parser* parser = &compiler->parser;
|
|
|
|
|
2021-06-09 18:42:26 +08:00
|
|
|
pkByteBuffer buff;
|
|
|
|
pkByteBufferInit(&buff);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
char quote = (single_quote) ? '\'' : '"';
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// For interpolated string it'll be TK_STRING_INTERP.
|
|
|
|
TokenType tk_type = TK_STRING;
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
while (true) {
|
2022-04-07 11:28:51 +08:00
|
|
|
char c = eatChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
if (c == quote) break;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
if (c == '\0') {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser), "Non terminated string.");
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
// Null byte is required by TK_EOF.
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->current_char--;
|
2021-02-12 01:35:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
if (c == '$') {
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->si_depth < MAX_STR_INTERP_DEPTH) {
|
2022-04-05 12:26:48 +08:00
|
|
|
tk_type = TK_STRING_INTERP;
|
2022-04-05 10:55:32 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
char c = peekChar(parser);
|
2022-04-05 12:26:48 +08:00
|
|
|
if (c == '{') { // Expression interpolation (ie. "${expr}").
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
|
|
|
parser->si_depth++;
|
|
|
|
parser->si_quote[parser->si_depth - 1] = quote;
|
|
|
|
parser->si_open_brace[parser->si_depth - 1] = 0;
|
2022-04-05 12:26:48 +08:00
|
|
|
|
|
|
|
} else { // Name Interpolation.
|
|
|
|
if (!utilIsName(c)) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser),
|
|
|
|
"Expected '{' or identifier after '$'.");
|
|
|
|
return;
|
2022-04-05 12:26:48 +08:00
|
|
|
|
|
|
|
} else { // Name interpolation (ie. "Hello $name!").
|
|
|
|
|
|
|
|
// The pointer [ptr] will points to the character at where the
|
|
|
|
// interpolated string ends. (ie. the next character after name
|
|
|
|
// ends).
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* ptr = parser->current_char;
|
2022-04-05 12:26:48 +08:00
|
|
|
while (utilIsName(*(ptr)) || utilIsDigit(*(ptr))) {
|
|
|
|
ptr++;
|
|
|
|
}
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->si_name_end = ptr;
|
|
|
|
parser->si_name_quote = quote;
|
2022-04-05 12:26:48 +08:00
|
|
|
}
|
2022-04-05 10:55:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, makeErrToken(parser),
|
|
|
|
"Maximum interpolation level reached (can only "
|
|
|
|
"interpolate upto depth %d).", MAX_STR_INTERP_DEPTH);
|
2022-04-05 10:55:32 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
if (c == '\\') {
|
2022-04-07 11:28:51 +08:00
|
|
|
switch (eatChar(parser)) {
|
|
|
|
case '"': pkByteBufferWrite(&buff, parser->vm, '"'); break;
|
|
|
|
case '\'': pkByteBufferWrite(&buff, parser->vm, '\''); break;
|
|
|
|
case '\\': pkByteBufferWrite(&buff, parser->vm, '\\'); break;
|
|
|
|
case 'n': pkByteBufferWrite(&buff, parser->vm, '\n'); break;
|
|
|
|
case 'r': pkByteBufferWrite(&buff, parser->vm, '\r'); break;
|
|
|
|
case 't': pkByteBufferWrite(&buff, parser->vm, '\t'); break;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// '$' In pocketlang string is used for interpolation.
|
2022-04-07 11:28:51 +08:00
|
|
|
case '$': pkByteBufferWrite(&buff, parser->vm, '$'); break;
|
2022-04-05 10:55:32 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
default:
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser),
|
|
|
|
"Invalid escape character.");
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
pkByteBufferWrite(&buff, parser->vm, c);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// '\0' will be added by varNewSring();
|
2022-04-07 11:28:51 +08:00
|
|
|
Var string = VAR_OBJ(newStringLength(parser->vm, (const char*)buff.data,
|
2021-06-07 13:54:06 +08:00
|
|
|
(uint32_t)buff.count));
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
pkByteBufferClear(&buff, parser->vm);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextValueToken(parser, tk_type, string);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
// Returns the current char of the compiler on.
|
2022-04-07 11:28:51 +08:00
|
|
|
static char peekChar(Parser* parser) {
|
|
|
|
return *parser->current_char;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
// Returns the next char of the compiler on.
|
2022-04-07 11:28:51 +08:00
|
|
|
static char peekNextChar(Parser* parser) {
|
|
|
|
if (peekChar(parser) == '\0') return '\0';
|
|
|
|
return *(parser->current_char + 1);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
// Advance the compiler by 1 char.
|
2022-04-07 11:28:51 +08:00
|
|
|
static char eatChar(Parser* parser) {
|
|
|
|
char c = peekChar(parser);
|
|
|
|
parser->current_char++;
|
|
|
|
if (c == '\n') parser->current_line++;
|
2021-02-12 01:35:43 +08:00
|
|
|
return c;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Complete lexing an identifier name.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void eatName(Parser* parser) {
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
char c = peekChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
while (utilIsName(c) || utilIsDigit(c)) {
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
|
|
|
c = peekChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* name_start = parser->token_start;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
TokenType type = TK_NAME;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
int length = (int)(parser->current_char - name_start);
|
2021-02-12 01:35:43 +08:00
|
|
|
for (int i = 0; _keywords[i].identifier != NULL; i++) {
|
|
|
|
if (_keywords[i].length == length &&
|
|
|
|
strncmp(name_start, _keywords[i].identifier, length) == 0) {
|
|
|
|
type = _keywords[i].tk_type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, type);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Complete lexing a number literal.
|
2022-04-22 20:21:17 +08:00
|
|
|
static void eatNumber(Compiler* compiler) {
|
|
|
|
Parser* parser = &compiler->parser;
|
2021-06-23 13:21:18 +08:00
|
|
|
|
|
|
|
#define IS_HEX_CHAR(c) \
|
|
|
|
(('0' <= (c) && (c) <= '9') || \
|
|
|
|
('a' <= (c) && (c) <= 'f'))
|
|
|
|
|
|
|
|
#define IS_BIN_CHAR(c) (((c) == '0') || ((c) == '1'))
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
Var value = VAR_NULL; // The number value.
|
2022-04-07 11:28:51 +08:00
|
|
|
char c = *parser->token_start;
|
2021-06-16 02:54:30 +08:00
|
|
|
|
|
|
|
// Binary literal.
|
2022-05-09 17:53:55 +08:00
|
|
|
if (c == '0' && ((peekChar(parser) == 'b') || (peekChar(parser) == 'B'))) {
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser); // Consume '0b'
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
uint64_t bin = 0;
|
2022-04-07 11:28:51 +08:00
|
|
|
c = peekChar(parser);
|
2021-06-23 13:21:18 +08:00
|
|
|
if (!IS_BIN_CHAR(c)) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser), "Invalid binary literal.");
|
|
|
|
return;
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
} else {
|
|
|
|
do {
|
2021-06-23 13:21:18 +08:00
|
|
|
// Consume the next digit.
|
2022-04-07 11:28:51 +08:00
|
|
|
c = peekChar(parser);
|
2021-06-23 13:21:18 +08:00
|
|
|
if (!IS_BIN_CHAR(c)) break;
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
// Check the length of the binary literal.
|
2022-04-07 11:28:51 +08:00
|
|
|
int length = (int)(parser->current_char - parser->token_start);
|
2021-06-16 02:54:30 +08:00
|
|
|
if (length > STR_BIN_BUFF_SIZE - 2) { // -2: '-\0' 0b is in both side.
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, makeErrToken(parser),
|
|
|
|
"Binary literal is too long.");
|
2021-06-16 02:54:30 +08:00
|
|
|
break;
|
|
|
|
}
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
// "Append" the next digit at the end.
|
|
|
|
bin = (bin << 1) | (c - '0');
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
} while (true);
|
|
|
|
}
|
2021-06-23 13:00:06 +08:00
|
|
|
value = VAR_NUM((double)bin);
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2022-05-09 17:53:55 +08:00
|
|
|
} else if (c == '0' &&
|
|
|
|
((peekChar(parser) == 'x') || (peekChar(parser) == 'X'))) {
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser); // Consume '0x'
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
uint64_t hex = 0;
|
2022-04-07 11:28:51 +08:00
|
|
|
c = peekChar(parser);
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-23 13:00:06 +08:00
|
|
|
// The first digit should be either hex digit.
|
2021-06-23 13:21:18 +08:00
|
|
|
if (!IS_HEX_CHAR(c)) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser), "Invalid hex literal.");
|
|
|
|
return;
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
} else {
|
|
|
|
do {
|
2021-06-23 13:21:18 +08:00
|
|
|
// Consume the next digit.
|
2022-04-07 11:28:51 +08:00
|
|
|
c = peekChar(parser);
|
2021-06-23 13:21:18 +08:00
|
|
|
if (!IS_HEX_CHAR(c)) break;
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
2021-06-16 02:54:30 +08:00
|
|
|
|
|
|
|
// Check the length of the binary literal.
|
2022-04-07 11:28:51 +08:00
|
|
|
int length = (int)(parser->current_char - parser->token_start);
|
2021-06-16 02:54:30 +08:00
|
|
|
if (length > STR_HEX_BUFF_SIZE - 2) { // -2: '-\0' 0x is in both side.
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, makeErrToken(parser),
|
|
|
|
"Hex literal is too long.");
|
2021-06-16 02:54:30 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// "Append" the next digit at the end.
|
|
|
|
uint8_t append_val = ('0' <= c && c <= '9')
|
|
|
|
? (uint8_t)(c - '0')
|
|
|
|
: (uint8_t)((c - 'a') + 10);
|
|
|
|
hex = (hex << 4) | append_val;
|
|
|
|
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
value = VAR_NUM((double)hex);
|
|
|
|
}
|
2021-06-23 13:21:18 +08:00
|
|
|
|
|
|
|
} else { // Regular number literal.
|
2022-05-09 17:53:55 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
while (utilIsDigit(peekChar(parser))) {
|
|
|
|
eatChar(parser);
|
2021-06-16 02:54:30 +08:00
|
|
|
}
|
|
|
|
|
2022-05-09 17:53:55 +08:00
|
|
|
if (c != '.') { // Number starts with a decimal point.
|
|
|
|
if (peekChar(parser) == '.' && utilIsDigit(peekNextChar(parser))) {
|
|
|
|
matchChar(parser, '.');
|
|
|
|
while (utilIsDigit(peekChar(parser))) {
|
|
|
|
eatChar(parser);
|
|
|
|
}
|
2021-06-23 13:00:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-23 13:21:18 +08:00
|
|
|
// Parse if in scientific notation format (MeN == M * 10 ** N).
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, 'e') || matchChar(parser, 'E')) {
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
if (peekChar(parser) == '+' || peekChar(parser) == '-') {
|
|
|
|
eatChar(parser);
|
2021-06-23 13:00:06 +08:00
|
|
|
}
|
2021-06-23 13:21:18 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
if (!utilIsDigit(peekChar(parser))) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, makeErrToken(parser), "Invalid number literal.");
|
|
|
|
return;
|
2021-06-23 13:21:18 +08:00
|
|
|
|
|
|
|
} else { // Eat the exponent.
|
2022-04-07 11:28:51 +08:00
|
|
|
while (utilIsDigit(peekChar(parser))) eatChar(parser);
|
2021-06-23 13:00:06 +08:00
|
|
|
}
|
2021-06-16 02:54:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
errno = 0;
|
2022-04-07 11:28:51 +08:00
|
|
|
value = VAR_NUM(atof(parser->token_start));
|
2021-06-16 02:54:30 +08:00
|
|
|
if (errno == ERANGE) {
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* start = parser->token_start;
|
|
|
|
int len = (int)(parser->current_char - start);
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, makeErrToken(parser),
|
|
|
|
"Number literal is too large (%.*s).", len, start);
|
2021-06-16 02:54:30 +08:00
|
|
|
value = VAR_NUM(0);
|
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextValueToken(parser, TK_NUMBER, value);
|
2021-06-23 13:21:18 +08:00
|
|
|
#undef IS_BIN_CHAR
|
|
|
|
#undef IS_HEX_CHAR
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Read and ignore chars till it reach new line or EOF.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void skipLineComment(Parser* parser) {
|
2021-02-15 20:49:19 +08:00
|
|
|
char c;
|
2022-04-07 11:28:51 +08:00
|
|
|
while ((c = peekChar(parser)) != '\0') {
|
2021-05-11 14:38:23 +08:00
|
|
|
// Don't eat new line it's not part of the comment.
|
2021-02-15 20:49:19 +08:00
|
|
|
if (c == '\n') return;
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the current char is [c] consume it and advance char by 1 and returns
|
|
|
|
// true otherwise returns false.
|
2022-04-07 11:28:51 +08:00
|
|
|
static bool matchChar(Parser* parser, char c) {
|
|
|
|
if (peekChar(parser) != c) return false;
|
|
|
|
eatChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
return true;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the current char is [c] eat the char and add token two otherwise eat
|
|
|
|
// append token one.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void setNextTwoCharToken(Parser* parser, char c, TokenType one,
|
2021-02-12 01:35:43 +08:00
|
|
|
TokenType two) {
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, c)) {
|
|
|
|
setNextToken(parser, two);
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, one);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
// Returns an error token from the current position for reporting error.
|
|
|
|
static Token makeErrToken(Parser* parser) {
|
|
|
|
Token tk;
|
|
|
|
tk.type = TK_ERROR;
|
|
|
|
tk.start = parser->token_start;
|
|
|
|
tk.length = (int)(parser->current_char - parser->token_start);
|
|
|
|
tk.line = parser->current_line;
|
|
|
|
return tk;
|
|
|
|
}
|
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
// Initialize the next token as the type.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void setNextToken(Parser* parser, TokenType type) {
|
|
|
|
Token* next = &parser->next;
|
2021-06-04 09:28:42 +08:00
|
|
|
next->type = type;
|
2022-04-07 11:28:51 +08:00
|
|
|
next->start = parser->token_start;
|
|
|
|
next->length = (int)(parser->current_char - parser->token_start);
|
|
|
|
next->line = parser->current_line - ((type == TK_LINE) ? 1 : 0);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the next token as the type and assign the value.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void setNextValueToken(Parser* parser, TokenType type, Var value) {
|
|
|
|
setNextToken(parser, type);
|
|
|
|
parser->next.value = value;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Lex the next token and set it as the next token.
|
2022-04-22 20:21:17 +08:00
|
|
|
static void lexToken(Compiler* compiler) {
|
|
|
|
Parser* parser = &compiler->parser;
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->previous = parser->current;
|
|
|
|
parser->current = parser->next;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->current.type == TK_EOF) return;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
while (peekChar(parser) != '\0') {
|
|
|
|
parser->token_start = parser->current_char;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-05 12:26:48 +08:00
|
|
|
// If we're parsing a name interpolation and the current character is where
|
|
|
|
// the name end, continue parsing the string.
|
|
|
|
//
|
|
|
|
// "Hello $name!"
|
|
|
|
// ^-- si_name_end
|
|
|
|
//
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->si_name_end != NULL) {
|
|
|
|
if (parser->current_char == parser->si_name_end) {
|
|
|
|
parser->si_name_end = NULL;
|
2022-04-22 20:21:17 +08:00
|
|
|
eatString(compiler, parser->si_name_quote == '\'');
|
2022-04-05 12:26:48 +08:00
|
|
|
return;
|
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
ASSERT(parser->current_char < parser->si_name_end, OOPS);
|
2022-04-05 12:26:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
char c = eatChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
switch (c) {
|
2022-04-05 10:55:32 +08:00
|
|
|
|
|
|
|
case '{': {
|
|
|
|
|
|
|
|
// If we're inside an interpolation, increase the open brace count
|
|
|
|
// of the current depth.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->si_depth > 0) {
|
|
|
|
parser->si_open_brace[parser->si_depth - 1]++;
|
2022-04-05 10:55:32 +08:00
|
|
|
}
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, TK_LBRACE);
|
2022-04-05 10:55:32 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
case '}': {
|
|
|
|
// If we're inside of an interpolated string.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->si_depth > 0) {
|
2022-04-05 10:55:32 +08:00
|
|
|
|
|
|
|
// No open braces, then end the expression and complete the string.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (parser->si_open_brace[parser->si_depth - 1] == 0) {
|
2022-04-05 10:55:32 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
char quote = parser->si_quote[parser->si_depth - 1];
|
|
|
|
parser->si_depth--; //< Exit the depth.
|
2022-04-22 20:21:17 +08:00
|
|
|
eatString(compiler, quote == '\'');
|
2022-04-05 10:55:32 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
} else { // Decrease the open brace at the current depth.
|
2022-04-07 11:28:51 +08:00
|
|
|
parser->si_open_brace[parser->si_depth - 1]--;
|
2022-04-05 10:55:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, TK_RBRACE);
|
2022-04-05 10:55:32 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
case ',': setNextToken(parser, TK_COMMA); return;
|
|
|
|
case ':': setNextToken(parser, TK_COLLON); return;
|
|
|
|
case ';': setNextToken(parser, TK_SEMICOLLON); return;
|
|
|
|
case '#': skipLineComment(parser); break;
|
|
|
|
case '(': setNextToken(parser, TK_LPARAN); return;
|
|
|
|
case ')': setNextToken(parser, TK_RPARAN); return;
|
|
|
|
case '[': setNextToken(parser, TK_LBRACKET); return;
|
|
|
|
case ']': setNextToken(parser, TK_RBRACKET); return;
|
2021-06-22 20:19:52 +08:00
|
|
|
case '%':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_PERCENT, TK_MODEQ);
|
2021-06-22 20:19:52 +08:00
|
|
|
return;
|
2021-05-18 19:21:38 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
case '~': setNextToken(parser, TK_TILD); return;
|
2021-06-15 00:20:07 +08:00
|
|
|
|
|
|
|
case '&':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_AMP, TK_ANDEQ);
|
2021-06-15 00:20:07 +08:00
|
|
|
return;
|
2021-06-16 02:54:30 +08:00
|
|
|
|
2021-06-15 12:36:10 +08:00
|
|
|
case '|':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_PIPE, TK_OREQ);
|
2021-06-15 12:36:10 +08:00
|
|
|
return;
|
2021-06-16 02:54:30 +08:00
|
|
|
|
2021-06-15 12:36:10 +08:00
|
|
|
case '^':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_CARET, TK_XOREQ);
|
2021-06-15 12:36:10 +08:00
|
|
|
return;
|
2021-05-18 19:21:38 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
case '\n': setNextToken(parser, TK_LINE); return;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\r': {
|
2022-04-07 11:28:51 +08:00
|
|
|
c = peekChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
while (c == ' ' || c == '\t' || c == '\r') {
|
2022-04-07 11:28:51 +08:00
|
|
|
eatChar(parser);
|
|
|
|
c = peekChar(parser);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-06-23 03:21:19 +08:00
|
|
|
case '.':
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, '.')) {
|
|
|
|
setNextToken(parser, TK_DOTDOT); // '..'
|
|
|
|
} else if (utilIsDigit(peekChar(parser))) {
|
|
|
|
eatChar(parser); // Consume the decimal point.
|
2022-04-22 20:21:17 +08:00
|
|
|
eatNumber(compiler); // Consume the rest of the number
|
|
|
|
if (parser->has_syntax_error) return;
|
2021-06-23 03:21:19 +08:00
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, TK_DOT); // '.'
|
2021-06-23 03:21:19 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '=':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_EQ, TK_EQEQ);
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '!':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_NOT, TK_NOTEQ);
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '>':
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, '>')) {
|
2022-05-08 18:02:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_SRIGHT, TK_SRIGHTEQ);
|
2021-06-23 22:24:20 +08:00
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_GT, TK_GTEQ);
|
2021-06-23 22:24:20 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '<':
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, '<')) {
|
2022-05-08 18:02:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_SLEFT, TK_SLEFTEQ);
|
2021-06-23 22:24:20 +08:00
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_LT, TK_LTEQ);
|
2021-06-23 22:24:20 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '+':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_PLUS, TK_PLUSEQ);
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '-':
|
2022-04-07 11:28:51 +08:00
|
|
|
if (matchChar(parser, '=')) {
|
|
|
|
setNextToken(parser, TK_MINUSEQ); // '-='
|
|
|
|
} else if (matchChar(parser, '>')) {
|
|
|
|
setNextToken(parser, TK_ARROW); // '->'
|
2021-05-16 15:05:54 +08:00
|
|
|
} else {
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, TK_MINUS); // '-'
|
2021-05-16 15:05:54 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '*':
|
2022-05-08 18:02:51 +08:00
|
|
|
if (matchChar(parser, '*')) {
|
|
|
|
setNextTwoCharToken(parser, '=', TK_STARSTAR, TK_POWEQ);
|
|
|
|
} else {
|
|
|
|
setNextTwoCharToken(parser, '=', TK_STAR, TK_STAREQ);
|
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
case '/':
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextTwoCharToken(parser, '=', TK_FSLASH, TK_DIVEQ);
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
case '"': eatString(compiler, false); return;
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
case '\'': eatString(compiler, true); return;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
default: {
|
|
|
|
|
|
|
|
if (utilIsDigit(c)) {
|
2022-04-22 20:21:17 +08:00
|
|
|
eatNumber(compiler);
|
|
|
|
if (parser->has_syntax_error) return;
|
2021-06-16 02:54:30 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
} else if (utilIsName(c)) {
|
2022-04-07 11:28:51 +08:00
|
|
|
eatName(parser);
|
2021-06-16 02:54:30 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
2022-04-22 20:21:17 +08:00
|
|
|
setNextToken(parser, TK_ERROR);
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
if (c >= 32 && c <= 126) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, parser->next,
|
|
|
|
"Invalid character '%c'", c);
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, parser->next,
|
|
|
|
"Invalid byte 0x%x", (uint8_t)c);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
parser->token_start = parser->current_char;
|
2022-04-07 11:28:51 +08:00
|
|
|
setNextToken(parser, TK_EOF);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* PARSING */
|
|
|
|
/*****************************************************************************/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 09:28:42 +08:00
|
|
|
// Returns current token type without lexing a new token.
|
2022-04-07 11:28:51 +08:00
|
|
|
static TokenType peek(Compiler* compiler) {
|
|
|
|
return compiler->parser.current.type;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Consume the current token if it's expected and lex for the next token
|
2021-06-15 15:37:49 +08:00
|
|
|
// and return true otherwise return false.
|
2022-04-07 11:28:51 +08:00
|
|
|
static bool match(Compiler* compiler, TokenType expected) {
|
|
|
|
if (peek(compiler) != expected) return false;
|
2022-04-22 20:21:17 +08:00
|
|
|
|
|
|
|
lexToken(compiler);
|
|
|
|
if (compiler->parser.has_syntax_error) return false;
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
return true;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-02-15 20:49:19 +08:00
|
|
|
// Consume the the current token and if it's not [expected] emits error log
|
|
|
|
// and continue parsing for more error logs.
|
2022-04-07 11:28:51 +08:00
|
|
|
static void consume(Compiler* compiler, TokenType expected,
|
|
|
|
const char* err_msg) {
|
2021-02-15 20:49:19 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
lexToken(compiler);
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
2021-02-15 20:49:19 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
Token *prev = &compiler->parser.previous;
|
|
|
|
if (prev->type != expected) {
|
|
|
|
syntaxError(compiler, *prev, "%s", err_msg);
|
|
|
|
return;
|
2021-02-15 20:49:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
// Match one or more lines and return true if there any.
|
2021-05-18 19:21:38 +08:00
|
|
|
static bool matchLine(Compiler* compiler) {
|
2021-06-09 18:42:26 +08:00
|
|
|
|
|
|
|
bool consumed = false;
|
|
|
|
|
|
|
|
if (peek(compiler) == TK_LINE) {
|
2022-04-22 20:21:17 +08:00
|
|
|
while (peek(compiler) == TK_LINE) {
|
|
|
|
lexToken(compiler);
|
|
|
|
if (compiler->parser.has_syntax_error) return false;
|
|
|
|
}
|
2021-06-09 18:42:26 +08:00
|
|
|
consumed = true;
|
|
|
|
}
|
|
|
|
|
2021-06-15 15:37:49 +08:00
|
|
|
// If we're running on REPL mode, at the EOF and compile time error occurred,
|
2021-06-09 18:42:26 +08:00
|
|
|
// signal the host to get more lines and try re-compiling it.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (compiler->parser.repl_mode && !compiler->parser.has_errors) {
|
2021-06-09 18:42:26 +08:00
|
|
|
if (peek(compiler) == TK_EOF) {
|
2022-04-07 11:28:51 +08:00
|
|
|
compiler->parser.need_more_lines = true;
|
2021-06-09 18:42:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return consumed;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Will skip multiple new lines.
|
|
|
|
static void skipNewLines(Compiler* compiler) {
|
|
|
|
matchLine(compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
// Match semi collon, multiple new lines or peek 'end', 'else' keywords.
|
2021-05-18 19:21:38 +08:00
|
|
|
static bool matchEndStatement(Compiler* compiler) {
|
|
|
|
if (match(compiler, TK_SEMICOLLON)) {
|
|
|
|
skipNewLines(compiler);
|
2021-02-15 20:49:19 +08:00
|
|
|
return true;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-05-22 21:27:40 +08:00
|
|
|
if (matchLine(compiler) || peek(compiler) == TK_EOF)
|
|
|
|
return true;
|
2021-02-15 20:49:19 +08:00
|
|
|
|
2021-06-15 15:37:49 +08:00
|
|
|
// In the below statement we don't require any new lines or semicolons.
|
2022-04-17 09:29:18 +08:00
|
|
|
// 'if cond then stmnt1 else if cond2 then stmnt2 else stmnt3 end'
|
|
|
|
if (peek(compiler) == TK_END || peek(compiler) == TK_ELSE)
|
2021-02-15 20:49:19 +08:00
|
|
|
return true;
|
2021-05-22 21:27:40 +08:00
|
|
|
|
2021-02-16 02:51:00 +08:00
|
|
|
return false;
|
2021-02-15 20:49:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Consume semi collon, multiple new lines or peek 'end' keyword.
|
2021-05-18 19:21:38 +08:00
|
|
|
static void consumeEndStatement(Compiler* compiler) {
|
|
|
|
if (!matchEndStatement(compiler)) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.current,
|
|
|
|
"Expected statement end with '\\n' or ';'.");
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-11 14:38:23 +08:00
|
|
|
// Match optional "do" or "then" keyword and new lines.
|
2021-05-18 19:21:38 +08:00
|
|
|
static void consumeStartBlock(Compiler* compiler, TokenType delimiter) {
|
2021-02-12 01:35:43 +08:00
|
|
|
bool consumed = false;
|
|
|
|
|
2021-05-11 14:38:23 +08:00
|
|
|
// Match optional "do" or "then".
|
|
|
|
if (delimiter == TK_DO || delimiter == TK_THEN) {
|
2021-05-18 19:21:38 +08:00
|
|
|
if (match(compiler, delimiter))
|
2021-05-11 14:38:23 +08:00
|
|
|
consumed = true;
|
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
if (matchLine(compiler))
|
2021-02-12 01:35:43 +08:00
|
|
|
consumed = true;
|
|
|
|
|
|
|
|
if (!consumed) {
|
2021-05-16 01:57:34 +08:00
|
|
|
const char* msg;
|
|
|
|
if (delimiter == TK_DO) msg = "Expected enter block with newline or 'do'.";
|
|
|
|
else msg = "Expected enter block with newline or 'then'.";
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous, msg);
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-02-15 20:49:19 +08:00
|
|
|
// Returns a optional compound assignment.
|
2021-05-18 19:21:38 +08:00
|
|
|
static bool matchAssignment(Compiler* compiler) {
|
2021-06-28 21:47:19 +08:00
|
|
|
if (match(compiler, TK_EQ)) return true;
|
|
|
|
if (match(compiler, TK_PLUSEQ)) return true;
|
|
|
|
if (match(compiler, TK_MINUSEQ)) return true;
|
|
|
|
if (match(compiler, TK_STAREQ)) return true;
|
|
|
|
if (match(compiler, TK_DIVEQ)) return true;
|
|
|
|
if (match(compiler, TK_MODEQ)) return true;
|
2022-05-08 18:02:51 +08:00
|
|
|
if (match(compiler, TK_POWEQ)) return true;
|
2021-06-28 21:47:19 +08:00
|
|
|
if (match(compiler, TK_ANDEQ)) return true;
|
|
|
|
if (match(compiler, TK_OREQ)) return true;
|
|
|
|
if (match(compiler, TK_XOREQ)) return true;
|
2021-06-23 22:24:20 +08:00
|
|
|
if (match(compiler, TK_SRIGHTEQ)) return true;
|
2021-06-28 21:47:19 +08:00
|
|
|
if (match(compiler, TK_SLEFTEQ)) return true;
|
|
|
|
|
2021-02-15 20:49:19 +08:00
|
|
|
return false;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
2022-04-07 11:28:51 +08:00
|
|
|
/* NAME SEARCH (AT COMPILATION PHASE) */
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2022-04-12 04:49:09 +08:00
|
|
|
// Find the builtin function name and returns it's index in the builtins array
|
|
|
|
// if not found returns -1.
|
|
|
|
static int findBuiltinFunction(const PKVM* vm,
|
|
|
|
const char* name, uint32_t length) {
|
|
|
|
for (int i = 0; i < vm->builtins_count; i++) {
|
2022-04-20 12:10:54 +08:00
|
|
|
uint32_t bfn_length = (uint32_t)strlen(vm->builtins_funcs[i]->fn->name);
|
2022-04-12 04:49:09 +08:00
|
|
|
if (bfn_length != length) continue;
|
2022-04-20 12:10:54 +08:00
|
|
|
if (strncmp(name, vm->builtins_funcs[i]->fn->name, length) == 0) {
|
2022-04-12 04:49:09 +08:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:05:33 +08:00
|
|
|
// Find the builtin classes name and returns it's index in the VM's builtin
|
|
|
|
// classes array, if not found returns -1.
|
|
|
|
static int findBuiltinClass(const PKVM* vm,
|
|
|
|
const char* name, uint32_t length) {
|
|
|
|
for (int i = 0; i < PK_INSTANCE; i++) {
|
|
|
|
uint32_t bfn_length = vm->builtin_classes[i]->name->length;
|
|
|
|
if (IS_CSTR_EQ(vm->builtin_classes[i]->name, name, length)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
// Find the local with the [name] in the given function [func] and return
|
|
|
|
// it's index, if not found returns -1.
|
|
|
|
static int findLocal(Func* func, const char* name, uint32_t length) {
|
2022-04-13 08:34:14 +08:00
|
|
|
ASSERT(func != NULL, OOPS);
|
2022-04-12 18:30:42 +08:00
|
|
|
for (int i = 0; i < func->local_count; i++) {
|
|
|
|
if (func->locals[i].length != length) continue;
|
|
|
|
if (strncmp(func->locals[i].name, name, length) == 0) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-04-13 08:34:14 +08:00
|
|
|
// Add the upvalue to the given function and return it's index, if the upvalue
|
|
|
|
// already present in the function's upvalue array it'll return it.
|
|
|
|
static int addUpvalue(Compiler* compiler, Func* func,
|
|
|
|
int index, bool is_immediate) {
|
|
|
|
|
|
|
|
// Search the upvalue in the existsing upvalues array.
|
|
|
|
for (int i = 0; i < func->ptr->upvalue_count; i++) {
|
|
|
|
UpvalueInfo info = func->upvalues[i];
|
|
|
|
if (info.index == index && info.is_immediate == is_immediate) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (func->ptr->upvalue_count == MAX_UPVALUES) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"A function cannot capture more thatn %d upvalues.", MAX_UPVALUES);
|
2022-04-13 08:34:14 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
func->upvalues[func->ptr->upvalue_count].index = index;
|
|
|
|
func->upvalues[func->ptr->upvalue_count].is_immediate = is_immediate;
|
|
|
|
return func->ptr->upvalue_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search for an upvalue with the given [name] for the current function [func].
|
|
|
|
// If an upvalue found, it'll add the upvalue info to the upvalue infor array
|
|
|
|
// of the [func] and return the index of the upvalue in the current function's
|
|
|
|
// upvalues array.
|
|
|
|
static int findUpvalue(Compiler* compiler, Func* func, const char* name,
|
|
|
|
uint32_t length) {
|
|
|
|
// TODO:
|
|
|
|
// check if the function is a method of a class and return -1 for them as
|
|
|
|
// well (once methods implemented).
|
|
|
|
//
|
|
|
|
// Toplevel functions cannot have upvalues.
|
|
|
|
if (func->depth <= DEPTH_GLOBAL) return -1;
|
|
|
|
|
|
|
|
// Search in the immediate enclosing function's locals.
|
|
|
|
int index = findLocal(func->outer_func, name, length);
|
|
|
|
if (index != -1) {
|
|
|
|
|
|
|
|
// Mark the locals as an upvalue to close it when it goes out of the scope.
|
|
|
|
func->outer_func->locals[index].is_upvalue = true;
|
|
|
|
|
|
|
|
// Add upvalue to the function and return it's index.
|
|
|
|
return addUpvalue(compiler, func, index, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recursively search for the upvalue in the outer function. If we found one
|
|
|
|
// all the outer function in the chain would have captured the upvalue for
|
|
|
|
// the local, we can add it to the current function as non-immediate upvalue.
|
|
|
|
index = findUpvalue(compiler, func->outer_func, name, length);
|
|
|
|
|
|
|
|
if (index != -1) {
|
|
|
|
return addUpvalue(compiler, func, index, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reached here, the upvalue doesn't exists.
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-02-11 01:23:48 +08:00
|
|
|
// Result type for an identifier definition.
|
|
|
|
typedef enum {
|
2021-02-12 01:35:43 +08:00
|
|
|
NAME_NOT_DEFINED,
|
|
|
|
NAME_LOCAL_VAR, //< Including parameter.
|
2022-04-13 08:34:14 +08:00
|
|
|
NAME_UPVALUE, //< Local to an enclosing function.
|
2021-02-12 01:35:43 +08:00
|
|
|
NAME_GLOBAL_VAR,
|
2022-04-20 18:05:33 +08:00
|
|
|
NAME_BUILTIN_FN, //< Native builtin function.
|
|
|
|
NAME_BUILTIN_TY, //< Builtin primitive type classes.
|
2021-02-11 01:23:48 +08:00
|
|
|
} NameDefnType;
|
|
|
|
|
|
|
|
// Identifier search result.
|
|
|
|
typedef struct {
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
NameDefnType type;
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Index in the variable/function buffer/array.
|
|
|
|
int index;
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// The line it declared.
|
|
|
|
int line;
|
2021-02-11 01:23:48 +08:00
|
|
|
|
|
|
|
} NameSearchResult;
|
|
|
|
|
|
|
|
// Will check if the name already defined.
|
|
|
|
static NameSearchResult compilerSearchName(Compiler* compiler,
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* name, uint32_t length) {
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
NameSearchResult result;
|
|
|
|
result.type = NAME_NOT_DEFINED;
|
2021-02-13 21:57:59 +08:00
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
int index; // For storing the search result below.
|
2021-02-13 21:57:59 +08:00
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
// Search through locals.
|
|
|
|
index = findLocal(compiler->func, name, length);
|
|
|
|
if (index != -1) {
|
|
|
|
result.type = NAME_LOCAL_VAR;
|
|
|
|
result.index = index;
|
|
|
|
return result;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
|
|
|
|
2022-04-13 08:34:14 +08:00
|
|
|
// Search through upvalues.
|
|
|
|
index = findUpvalue(compiler, compiler->func, name, length);
|
|
|
|
if (index != -1) {
|
|
|
|
result.type = NAME_UPVALUE;
|
|
|
|
result.index = index;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
// Search through globals.
|
2022-04-11 16:04:22 +08:00
|
|
|
index = moduleGetGlobalIndex(compiler->module, name, length);
|
2021-06-04 22:55:06 +08:00
|
|
|
if (index != -1) {
|
|
|
|
result.type = NAME_GLOBAL_VAR;
|
|
|
|
result.index = index;
|
|
|
|
return result;
|
|
|
|
}
|
2021-06-10 07:35:14 +08:00
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
// Search through builtin functions.
|
2022-04-07 11:28:51 +08:00
|
|
|
index = findBuiltinFunction(compiler->parser.vm, name, length);
|
2021-02-13 01:40:19 +08:00
|
|
|
if (index != -1) {
|
2022-04-13 17:01:57 +08:00
|
|
|
result.type = NAME_BUILTIN_FN;
|
2021-02-13 01:40:19 +08:00
|
|
|
result.index = index;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-04-20 18:05:33 +08:00
|
|
|
index = findBuiltinClass(compiler->parser.vm, name, length);
|
|
|
|
if (index != -1) {
|
|
|
|
result.type = NAME_BUILTIN_TY;
|
|
|
|
result.index = index;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
return result;
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* PARSING GRAMMAR */
|
|
|
|
/*****************************************************************************/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
// Forward declaration of codegen functions.
|
|
|
|
static void emitOpcode(Compiler* compiler, Opcode opcode);
|
|
|
|
static int emitByte(Compiler* compiler, int byte);
|
|
|
|
static int emitShort(Compiler* compiler, int arg);
|
2021-05-20 22:05:57 +08:00
|
|
|
|
2021-06-14 02:41:13 +08:00
|
|
|
static void emitLoopJump(Compiler* compiler);
|
2022-04-13 10:23:54 +08:00
|
|
|
static void emitAssignedOp(Compiler* compiler, TokenType assignment);
|
2021-06-16 02:54:30 +08:00
|
|
|
static void emitFunctionEnd(Compiler* compiler);
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2021-05-16 01:57:34 +08:00
|
|
|
static void patchJump(Compiler* compiler, int addr_index);
|
2022-04-05 10:55:32 +08:00
|
|
|
static void patchListSize(Compiler* compiler, int size_index, int size);
|
2021-06-04 09:28:42 +08:00
|
|
|
static void patchForward(Compiler* compiler, Fn* fn, int index, int name);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
static int compilerAddConstant(Compiler* compiler, Var value);
|
2021-02-11 01:23:48 +08:00
|
|
|
static int compilerAddVariable(Compiler* compiler, const char* name,
|
2021-06-08 00:56:56 +08:00
|
|
|
uint32_t length, int line);
|
2021-05-20 22:05:57 +08:00
|
|
|
static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
|
2022-04-22 20:21:17 +08:00
|
|
|
Token* tkname);
|
2022-04-03 19:29:03 +08:00
|
|
|
static void compilerChangeStack(Compiler* compiler, int num);
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
// Forward declaration of grammar functions.
|
2021-02-09 16:21:10 +08:00
|
|
|
static void parsePrecedence(Compiler* compiler, Precedence precedence);
|
2022-04-26 18:23:30 +08:00
|
|
|
static void compileFunction(Compiler* compiler, FuncType fn_type);
|
2021-02-09 16:21:10 +08:00
|
|
|
static void compileExpression(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprLiteral(Compiler* compiler);
|
2022-04-05 10:55:32 +08:00
|
|
|
static void exprInterpolation(Compiler* compiler);
|
2022-04-17 09:29:18 +08:00
|
|
|
static void exprFunction(Compiler* compiler);
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprName(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprOr(Compiler* compiler);
|
|
|
|
static void exprAnd(Compiler* compiler);
|
2021-05-16 01:57:34 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprBinaryOp(Compiler* compiler);
|
|
|
|
static void exprUnaryOp(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprGrouping(Compiler* compiler);
|
|
|
|
static void exprList(Compiler* compiler);
|
|
|
|
static void exprMap(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprCall(Compiler* compiler);
|
|
|
|
static void exprAttrib(Compiler* compiler);
|
|
|
|
static void exprSubscript(Compiler* compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-11 01:23:48 +08:00
|
|
|
// true, false, null, self.
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprValue(Compiler* compiler);
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
static void exprSelf(Compiler* compiler);
|
2022-05-01 21:12:13 +08:00
|
|
|
static void exprSuper(Compiler* compiler);
|
2022-04-21 19:53:03 +08:00
|
|
|
|
2021-02-07 15:40:00 +08:00
|
|
|
#define NO_RULE { NULL, NULL, PREC_NONE }
|
|
|
|
#define NO_INFIX PREC_NONE
|
|
|
|
|
|
|
|
GrammarRule rules[] = { // Prefix Infix Infix Precedence
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_ERROR */ NO_RULE,
|
|
|
|
/* TK_EOF */ NO_RULE,
|
|
|
|
/* TK_LINE */ NO_RULE,
|
2021-02-16 02:51:00 +08:00
|
|
|
/* TK_DOT */ { NULL, exprAttrib, PREC_ATTRIB },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_DOTDOT */ { NULL, exprBinaryOp, PREC_RANGE },
|
|
|
|
/* TK_COMMA */ NO_RULE,
|
|
|
|
/* TK_COLLON */ NO_RULE,
|
|
|
|
/* TK_SEMICOLLON */ NO_RULE,
|
|
|
|
/* TK_HASH */ NO_RULE,
|
|
|
|
/* TK_LPARAN */ { exprGrouping, exprCall, PREC_CALL },
|
|
|
|
/* TK_RPARAN */ NO_RULE,
|
2021-02-13 01:40:19 +08:00
|
|
|
/* TK_LBRACKET */ { exprList, exprSubscript, PREC_SUBSCRIPT },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_RBRACKET */ NO_RULE,
|
|
|
|
/* TK_LBRACE */ { exprMap, NULL, NO_INFIX },
|
|
|
|
/* TK_RBRACE */ NO_RULE,
|
|
|
|
/* TK_PERCENT */ { NULL, exprBinaryOp, PREC_FACTOR },
|
|
|
|
/* TK_TILD */ { exprUnaryOp, NULL, NO_INFIX },
|
|
|
|
/* TK_AMP */ { NULL, exprBinaryOp, PREC_BITWISE_AND },
|
|
|
|
/* TK_PIPE */ { NULL, exprBinaryOp, PREC_BITWISE_OR },
|
|
|
|
/* TK_CARET */ { NULL, exprBinaryOp, PREC_BITWISE_XOR },
|
2022-04-03 23:33:12 +08:00
|
|
|
/* TK_ARROW */ NO_RULE,
|
2022-04-29 02:33:20 +08:00
|
|
|
/* TK_PLUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_MINUS */ { exprUnaryOp, exprBinaryOp, PREC_TERM },
|
|
|
|
/* TK_STAR */ { NULL, exprBinaryOp, PREC_FACTOR },
|
|
|
|
/* TK_FSLASH */ { NULL, exprBinaryOp, PREC_FACTOR },
|
2022-05-08 18:02:51 +08:00
|
|
|
/* TK_STARSTAR */ { NULL, exprBinaryOp, PREC_EXPONENT },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_BSLASH */ NO_RULE,
|
2021-06-02 17:33:29 +08:00
|
|
|
/* TK_EQ */ NO_RULE,
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_GT */ { NULL, exprBinaryOp, PREC_COMPARISION },
|
|
|
|
/* TK_LT */ { NULL, exprBinaryOp, PREC_COMPARISION },
|
|
|
|
/* TK_EQEQ */ { NULL, exprBinaryOp, PREC_EQUALITY },
|
|
|
|
/* TK_NOTEQ */ { NULL, exprBinaryOp, PREC_EQUALITY },
|
|
|
|
/* TK_GTEQ */ { NULL, exprBinaryOp, PREC_COMPARISION },
|
|
|
|
/* TK_LTEQ */ { NULL, exprBinaryOp, PREC_COMPARISION },
|
2021-06-02 17:33:29 +08:00
|
|
|
/* TK_PLUSEQ */ NO_RULE,
|
|
|
|
/* TK_MINUSEQ */ NO_RULE,
|
|
|
|
/* TK_STAREQ */ NO_RULE,
|
|
|
|
/* TK_DIVEQ */ NO_RULE,
|
2021-06-22 20:19:52 +08:00
|
|
|
/* TK_MODEQ */ NO_RULE,
|
2022-05-08 18:02:51 +08:00
|
|
|
/* TK_POWEQ */ NO_RULE,
|
2021-06-15 00:20:07 +08:00
|
|
|
/* TK_ANDEQ */ NO_RULE,
|
2021-06-15 12:36:10 +08:00
|
|
|
/* TK_OREQ */ NO_RULE,
|
|
|
|
/* TK_XOREQ */ NO_RULE,
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_SRIGHT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
|
|
|
/* TK_SLEFT */ { NULL, exprBinaryOp, PREC_BITWISE_SHIFT },
|
2021-06-23 22:24:20 +08:00
|
|
|
/* TK_SRIGHTEQ */ NO_RULE,
|
|
|
|
/* TK_SLEFTEQ */ NO_RULE,
|
2021-06-20 23:28:31 +08:00
|
|
|
/* TK_CLASS */ NO_RULE,
|
2021-05-10 03:00:59 +08:00
|
|
|
/* TK_FROM */ NO_RULE,
|
2021-05-09 20:31:36 +08:00
|
|
|
/* TK_IMPORT */ NO_RULE,
|
|
|
|
/* TK_AS */ NO_RULE,
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_DEF */ NO_RULE,
|
|
|
|
/* TK_EXTERN */ NO_RULE,
|
2022-05-07 13:48:06 +08:00
|
|
|
/* TK_FN */ { exprFunction, NULL, NO_INFIX },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_END */ NO_RULE,
|
|
|
|
/* TK_NULL */ { exprValue, NULL, NO_INFIX },
|
2021-06-23 18:21:59 +08:00
|
|
|
/* TK_IN */ { NULL, exprBinaryOp, PREC_TEST },
|
2022-04-27 00:27:35 +08:00
|
|
|
/* TK_IS */ { NULL, exprBinaryOp, PREC_TEST },
|
2021-05-16 01:57:34 +08:00
|
|
|
/* TK_AND */ { NULL, exprAnd, PREC_LOGICAL_AND },
|
|
|
|
/* TK_OR */ { NULL, exprOr, PREC_LOGICAL_OR },
|
2021-06-23 18:21:59 +08:00
|
|
|
/* TK_NOT */ { exprUnaryOp, NULL, PREC_UNARY },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_TRUE */ { exprValue, NULL, NO_INFIX },
|
|
|
|
/* TK_FALSE */ { exprValue, NULL, NO_INFIX },
|
2022-05-01 21:12:13 +08:00
|
|
|
/* TK_SELF */ { exprSelf, NULL, NO_INFIX },
|
|
|
|
/* TK_SUPER */ { exprSuper, NULL, NO_INFIX },
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_DO */ NO_RULE,
|
2021-05-11 14:38:23 +08:00
|
|
|
/* TK_THEN */ NO_RULE,
|
2021-02-12 01:35:43 +08:00
|
|
|
/* TK_WHILE */ NO_RULE,
|
|
|
|
/* TK_FOR */ NO_RULE,
|
|
|
|
/* TK_IF */ NO_RULE,
|
|
|
|
/* TK_ELSE */ NO_RULE,
|
|
|
|
/* TK_BREAK */ NO_RULE,
|
|
|
|
/* TK_CONTINUE */ NO_RULE,
|
|
|
|
/* TK_RETURN */ NO_RULE,
|
|
|
|
/* TK_NAME */ { exprName, NULL, NO_INFIX },
|
|
|
|
/* TK_NUMBER */ { exprLiteral, NULL, NO_INFIX },
|
|
|
|
/* TK_STRING */ { exprLiteral, NULL, NO_INFIX },
|
2022-04-05 10:55:32 +08:00
|
|
|
/* TK_STRING_INTERP */ { exprInterpolation, NULL, NO_INFIX },
|
2021-02-07 15:40:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static GrammarRule* getRule(TokenType type) {
|
2021-02-12 01:35:43 +08:00
|
|
|
return &(rules[(int)type]);
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
// FIXME:
|
|
|
|
// This function is used by the import system, remove this function (and move
|
|
|
|
// it to emitStoreName()) after import system refactored.
|
|
|
|
//
|
|
|
|
// Store the value at the stack top to the global at the [index].
|
|
|
|
static void emitStoreGlobal(Compiler* compiler, int index) {
|
|
|
|
emitOpcode(compiler, OP_STORE_GLOBAL);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// Emit opcode to push the value of [type] at the [index] in it's array.
|
|
|
|
static void emitPushValue(Compiler* compiler, NameDefnType type, int index) {
|
2022-04-13 17:01:57 +08:00
|
|
|
ASSERT(index >= 0, OOPS);
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
switch (type) {
|
2022-04-22 20:21:17 +08:00
|
|
|
case NAME_NOT_DEFINED: {
|
|
|
|
if (compiler->parser.has_errors) {
|
|
|
|
return;
|
|
|
|
}
|
2022-04-13 10:23:54 +08:00
|
|
|
UNREACHABLE();
|
2022-04-22 20:21:17 +08:00
|
|
|
}
|
2022-04-13 10:23:54 +08:00
|
|
|
|
|
|
|
case NAME_LOCAL_VAR:
|
|
|
|
if (index < 9) { //< 0..8 locals have single opcode.
|
|
|
|
emitOpcode(compiler, (Opcode)(OP_PUSH_LOCAL_0 + index));
|
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_PUSH_LOCAL_N);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
}
|
|
|
|
return;
|
2022-04-13 17:01:57 +08:00
|
|
|
|
|
|
|
case NAME_UPVALUE:
|
|
|
|
emitOpcode(compiler, OP_PUSH_UPVALUE);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
return;
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
case NAME_GLOBAL_VAR:
|
|
|
|
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
2021-06-04 22:55:06 +08:00
|
|
|
emitByte(compiler, index);
|
2022-04-13 10:23:54 +08:00
|
|
|
return;
|
2022-04-13 17:01:57 +08:00
|
|
|
|
|
|
|
case NAME_BUILTIN_FN:
|
2022-04-13 10:23:54 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_BUILTIN_FN);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
return;
|
2022-04-20 18:05:33 +08:00
|
|
|
|
|
|
|
case NAME_BUILTIN_TY:
|
|
|
|
emitOpcode(compiler, OP_PUSH_BUILTIN_TY);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// Emit opcode to store the stack top value to the named value to the [type]
|
|
|
|
// at the [index] in it's array.
|
|
|
|
static void emitStoreValue(Compiler* compiler, NameDefnType type, int index) {
|
2022-04-13 17:01:57 +08:00
|
|
|
ASSERT(index >= 0, OOPS);
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
switch (type) {
|
|
|
|
case NAME_NOT_DEFINED:
|
2022-04-13 17:01:57 +08:00
|
|
|
case NAME_BUILTIN_FN:
|
2022-04-22 20:21:17 +08:00
|
|
|
case NAME_BUILTIN_TY: {
|
|
|
|
if (compiler->parser.has_errors) return;
|
2022-04-13 10:23:54 +08:00
|
|
|
UNREACHABLE();
|
2022-04-22 20:21:17 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
case NAME_LOCAL_VAR:
|
|
|
|
if (index < 9) { //< 0..8 locals have single opcode.
|
|
|
|
emitOpcode(compiler, (Opcode)(OP_STORE_LOCAL_0 + index));
|
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_STORE_LOCAL_N);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
}
|
|
|
|
return;
|
2022-04-13 17:01:57 +08:00
|
|
|
|
|
|
|
case NAME_UPVALUE:
|
|
|
|
emitOpcode(compiler, OP_STORE_UPVALUE);
|
|
|
|
emitByte(compiler, index);
|
|
|
|
return;
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
case NAME_GLOBAL_VAR:
|
|
|
|
emitStoreGlobal(compiler, index);
|
|
|
|
return;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2022-05-07 13:48:06 +08:00
|
|
|
// This function is reused between calls and method calls. if the [call_type]
|
|
|
|
// is OP_METHOD_CALL the [method] should refer a string in the module's
|
|
|
|
// constant pool, otherwise it's ignored.
|
|
|
|
static void _compileCall(Compiler* compiler, Opcode call_type, int method) {
|
|
|
|
ASSERT((call_type == OP_CALL) ||
|
|
|
|
(call_type == OP_METHOD_CALL) ||
|
|
|
|
(call_type == OP_SUPER_CALL), OOPS);
|
|
|
|
// Compile parameters.
|
|
|
|
int argc = 0;
|
|
|
|
|
|
|
|
if (compiler->parser.optional_call_paran) {
|
|
|
|
compiler->parser.optional_call_paran = false;
|
|
|
|
compileExpression(compiler);
|
|
|
|
argc = 1;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (!match(compiler, TK_RPARAN)) {
|
|
|
|
do {
|
|
|
|
skipNewLines(compiler);
|
|
|
|
compileExpression(compiler);
|
|
|
|
skipNewLines(compiler);
|
|
|
|
argc++;
|
|
|
|
} while (match(compiler, TK_COMMA));
|
|
|
|
consume(compiler, TK_RPARAN, "Expected ')' after parameter list.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emitOpcode(compiler, call_type);
|
|
|
|
|
|
|
|
emitByte(compiler, argc);
|
|
|
|
|
|
|
|
if ((call_type == OP_METHOD_CALL) || (call_type == OP_SUPER_CALL)) {
|
|
|
|
ASSERT_INDEX(method, (int)compiler->module->constants.count);
|
|
|
|
emitShort(compiler, method);
|
|
|
|
}
|
|
|
|
|
|
|
|
// After the call the arguments will be popped and the callable
|
|
|
|
// will be replaced with the return value.
|
|
|
|
compilerChangeStack(compiler, -argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Like lua, we're omitting the paranthese for literals, it'll check for
|
|
|
|
// literals that can be passed for no pranthese call (a syntax sugar) and
|
|
|
|
// emit the call. Return true if such call matched. If [method] >= 0 it'll
|
|
|
|
// compile a method call otherwise a regular call.
|
|
|
|
static bool _compileOptionalParanCall(Compiler* compiler, int method) {
|
|
|
|
static TokenType tk[] = {
|
|
|
|
TK_FN,
|
|
|
|
//TK_STRING,
|
|
|
|
//TK_STRING_INTERP,
|
|
|
|
TK_ERROR, // Sentinel to stop the iteration.
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; tk[i] != TK_ERROR; i++) {
|
|
|
|
if (peek(compiler) == tk[i]) {
|
|
|
|
compiler->parser.optional_call_paran = true;
|
|
|
|
Opcode call_type = ((method >= 0) ? OP_METHOD_CALL : OP_CALL);
|
|
|
|
_compileCall(compiler, call_type, method);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprLiteral(Compiler* compiler) {
|
2022-04-07 11:28:51 +08:00
|
|
|
Token* value = &compiler->parser.previous;
|
2021-02-12 01:35:43 +08:00
|
|
|
int index = compilerAddConstant(compiler, value->value);
|
2021-05-16 15:05:54 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_CONSTANT);
|
2021-02-12 01:35:43 +08:00
|
|
|
emitShort(compiler, index);
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// Consider the bellow string.
|
|
|
|
//
|
|
|
|
// "Hello $name!"
|
|
|
|
//
|
|
|
|
// This will be compiled as:
|
|
|
|
//
|
|
|
|
// list_join(["Hello ", name, "!"])
|
|
|
|
//
|
|
|
|
static void exprInterpolation(Compiler* compiler) {
|
|
|
|
emitOpcode(compiler, OP_PUSH_BUILTIN_FN);
|
|
|
|
emitByte(compiler, compiler->bifn_list_join);
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_PUSH_LIST);
|
|
|
|
int size_index = emitShort(compiler, 0);
|
|
|
|
|
|
|
|
int size = 0;
|
|
|
|
do {
|
|
|
|
// Push the string on the stack and append it to the list.
|
|
|
|
exprLiteral(compiler);
|
|
|
|
emitOpcode(compiler, OP_LIST_APPEND);
|
|
|
|
size++;
|
|
|
|
|
|
|
|
// Compile the expression and append it to the list.
|
|
|
|
skipNewLines(compiler);
|
|
|
|
compileExpression(compiler);
|
|
|
|
emitOpcode(compiler, OP_LIST_APPEND);
|
|
|
|
size++;
|
|
|
|
skipNewLines(compiler);
|
|
|
|
} while (match(compiler, TK_STRING_INTERP));
|
|
|
|
|
|
|
|
// The last string is not TK_STRING_INTERP but it would be
|
|
|
|
// TK_STRING. Apped it.
|
2022-04-06 11:26:51 +08:00
|
|
|
// Optimize case last string could be empty. Skip it.
|
2022-04-05 10:55:32 +08:00
|
|
|
consume(compiler, TK_STRING, "Non terminated interpolated string.");
|
2022-04-07 11:28:51 +08:00
|
|
|
if (compiler->parser.previous.type == TK_STRING /* != if syntax error. */) {
|
|
|
|
ASSERT(IS_OBJ_TYPE(compiler->parser.previous.value, OBJ_STRING), OOPS);
|
|
|
|
String* str = (String*)AS_OBJ(compiler->parser.previous.value);
|
2022-04-06 11:26:51 +08:00
|
|
|
if (str->length != 0) {
|
|
|
|
exprLiteral(compiler);
|
|
|
|
emitOpcode(compiler, OP_LIST_APPEND);
|
|
|
|
size++;
|
|
|
|
}
|
|
|
|
}
|
2022-04-05 10:55:32 +08:00
|
|
|
|
|
|
|
patchListSize(compiler, size_index, size);
|
|
|
|
|
|
|
|
// Call the list_join function (which is at the stack top).
|
|
|
|
emitOpcode(compiler, OP_CALL);
|
|
|
|
emitByte(compiler, 1);
|
|
|
|
|
2022-04-06 11:26:51 +08:00
|
|
|
// After the above call, the lits and the "list_join" function will be popped
|
|
|
|
// from the stack and a string will be pushed. The so the result stack effect
|
|
|
|
// is -1.
|
|
|
|
compilerChangeStack(compiler, -1);
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
}
|
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
static void exprFunction(Compiler* compiler) {
|
2022-04-21 19:53:03 +08:00
|
|
|
compileFunction(compiler, FUNC_LITERAL);
|
2021-02-13 21:57:59 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprName(Compiler* compiler) {
|
2021-02-15 20:49:19 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
Token tkname = compiler->parser.previous;
|
|
|
|
|
|
|
|
const char* start = tkname.start;
|
|
|
|
int length = tkname.length;
|
|
|
|
int line = tkname.line;
|
2021-06-04 09:28:42 +08:00
|
|
|
NameSearchResult result = compilerSearchName(compiler, start, length);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
if (compiler->l_value && matchAssignment(compiler)) {
|
|
|
|
TokenType assignment = compiler->parser.previous.type;
|
|
|
|
skipNewLines(compiler);
|
2021-06-20 08:49:35 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
// Type of the name that's being assigned. Could only be local, global
|
|
|
|
// or an upvalue.
|
|
|
|
NameDefnType name_type = result.type;
|
|
|
|
int index = result.index; // Index of the name in it's array.
|
|
|
|
|
|
|
|
// Will be set to true if the name is a new local.
|
|
|
|
bool new_local = false;
|
|
|
|
|
|
|
|
if (assignment == TK_EQ) { // name = (expr);
|
|
|
|
|
|
|
|
// Assignment to builtin functions will override the name and it'll
|
|
|
|
// become a local or global variable. Note that if the names is a global
|
|
|
|
// which hasent defined yet we treat that as a local (no global keyword
|
|
|
|
// like python does) and it's recommented to define all the globals
|
|
|
|
// before entering a local scope.
|
|
|
|
|
2022-04-20 18:05:33 +08:00
|
|
|
if (result.type == NAME_NOT_DEFINED ||
|
|
|
|
result.type == NAME_BUILTIN_FN ||
|
|
|
|
result.type == NAME_BUILTIN_TY ) {
|
2022-04-13 10:23:54 +08:00
|
|
|
name_type = (compiler->scope_depth == DEPTH_GLOBAL)
|
|
|
|
? NAME_GLOBAL_VAR
|
|
|
|
: NAME_LOCAL_VAR;
|
|
|
|
index = compilerAddVariable(compiler, start, length, line);
|
|
|
|
|
|
|
|
// We cannot set `compiler->new_local = true;` here since there is an
|
|
|
|
// expression after the assignment pending. We'll update it once the
|
|
|
|
// expression is compiled.
|
|
|
|
if (name_type == NAME_LOCAL_VAR) {
|
|
|
|
new_local = true;
|
|
|
|
}
|
|
|
|
}
|
2021-06-04 22:55:06 +08:00
|
|
|
|
|
|
|
// Compile the assigned value.
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler);
|
2021-06-04 22:55:06 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
} else { // name += / -= / *= ... = (expr);
|
2022-04-22 20:21:17 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
if (result.type == NAME_NOT_DEFINED) {
|
2022-04-22 20:21:17 +08:00
|
|
|
|
|
|
|
// TODO:
|
|
|
|
// Add to forward names. Create result.type as NAME_FORWARD
|
|
|
|
// and use emitPushName, emitStoreName for here and bellow.
|
|
|
|
semanticError(compiler, tkname,
|
|
|
|
"Name '%.*s' is not defined.", length, start);
|
2021-02-25 17:03:06 +08:00
|
|
|
}
|
2022-04-13 10:23:54 +08:00
|
|
|
|
|
|
|
// Push the named value.
|
2022-04-26 18:23:30 +08:00
|
|
|
emitPushValue(compiler, name_type, index);
|
2022-04-13 10:23:54 +08:00
|
|
|
|
|
|
|
// Compile the RHS of the assigned operation.
|
|
|
|
compileExpression(compiler);
|
|
|
|
|
|
|
|
// Do the arithmatic operation of the assignment.
|
|
|
|
emitAssignedOp(compiler, assignment);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's a new local we don't have to store it, it's already at it's
|
|
|
|
// stack slot.
|
|
|
|
if (new_local) {
|
|
|
|
// This will prevent the assignment from being popped out from the
|
|
|
|
// stack since the assigned value itself is the local and not a temp.
|
|
|
|
compiler->new_local = true;
|
|
|
|
|
|
|
|
// Ensure the local variable's index is equals to the stack top index.
|
|
|
|
// If the compiler has errors, we cannot and don't have to assert.
|
|
|
|
ASSERT(compiler->parser.has_errors ||
|
|
|
|
(compiler->func->stack_size - 1) == index, OOPS);
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
2022-04-13 10:23:54 +08:00
|
|
|
// The assigned value or the result of the operator will be at the top of
|
|
|
|
// the stack by now. Store it.
|
2022-04-26 18:23:30 +08:00
|
|
|
emitStoreValue(compiler, name_type, index);
|
2022-04-13 10:23:54 +08:00
|
|
|
}
|
2021-05-20 22:05:57 +08:00
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
} else { // Just the name and no assignment followed by.
|
|
|
|
|
|
|
|
// The name could be a global value which hasn't been defined at this
|
|
|
|
// point. We add an implicit forward declaration and once this expression
|
|
|
|
// executed the value could be initialized only if the expression is at
|
|
|
|
// a local depth.
|
|
|
|
if (result.type == NAME_NOT_DEFINED) {
|
2022-04-10 11:07:44 +08:00
|
|
|
if (compiler->scope_depth == DEPTH_GLOBAL) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, tkname,
|
|
|
|
"Name '%.*s' is not defined.", length, start);
|
2022-04-10 11:07:44 +08:00
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_PUSH_GLOBAL);
|
2021-06-04 22:55:06 +08:00
|
|
|
int index = emitByte(compiler, 0xff);
|
2022-04-22 20:21:17 +08:00
|
|
|
compilerAddForward(compiler, index, _FN, &tkname);
|
2021-05-20 22:05:57 +08:00
|
|
|
}
|
2022-04-13 10:23:54 +08:00
|
|
|
} else {
|
2022-04-26 18:23:30 +08:00
|
|
|
emitPushValue(compiler, result.type, result.index);
|
2021-06-13 04:17:44 +08:00
|
|
|
}
|
2022-05-07 13:48:06 +08:00
|
|
|
|
|
|
|
_compileOptionalParanCall(compiler, -1);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2022-04-13 10:23:54 +08:00
|
|
|
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2022-04-03 19:29:03 +08:00
|
|
|
// Compiling (expr a) or (expr b)
|
|
|
|
//
|
|
|
|
// (expr a)
|
|
|
|
// | At this point (expr a) is at the stack top.
|
|
|
|
// V
|
|
|
|
// .-- (OP_OR [offset])
|
|
|
|
// | | if true short circuit and skip (expr b)
|
|
|
|
// | | otherwise pop (expr a) and continue.
|
|
|
|
// | V
|
|
|
|
// | (expr b)
|
|
|
|
// | | At this point (expr b) is at the stack top.
|
|
|
|
// | V
|
|
|
|
// '-> (...)
|
|
|
|
// At this point stack top would be
|
|
|
|
// either (expr a) or (expr b)
|
|
|
|
//
|
|
|
|
// Compiling 'and' expression is also similler but we jump if the (expr a) is
|
|
|
|
// false.
|
2021-05-16 01:57:34 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
void exprOr(Compiler* compiler) {
|
2022-04-03 19:29:03 +08:00
|
|
|
emitOpcode(compiler, OP_OR);
|
|
|
|
int orpatch = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-05-16 01:57:34 +08:00
|
|
|
parsePrecedence(compiler, PREC_LOGICAL_OR);
|
2022-04-03 19:29:03 +08:00
|
|
|
patchJump(compiler, orpatch);
|
2021-05-16 01:57:34 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
void exprAnd(Compiler* compiler) {
|
2022-04-03 19:29:03 +08:00
|
|
|
emitOpcode(compiler, OP_AND);
|
|
|
|
int andpatch = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-05-16 01:57:34 +08:00
|
|
|
parsePrecedence(compiler, PREC_LOGICAL_AND);
|
2022-04-03 19:29:03 +08:00
|
|
|
patchJump(compiler, andpatch);
|
2021-05-16 01:57:34 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprBinaryOp(Compiler* compiler) {
|
2022-04-07 11:28:51 +08:00
|
|
|
TokenType op = compiler->parser.previous.type;
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
parsePrecedence(compiler, (Precedence)(getRule(op)->precedence + 1));
|
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
// Emits the opcode and 0 (means false) as inplace operation.
|
|
|
|
#define EMIT_BINARY_OP_INPLACE(opcode)\
|
|
|
|
do { emitOpcode(compiler, opcode); emitByte(compiler, 0); } while (false)
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
switch (op) {
|
2022-05-08 18:02:51 +08:00
|
|
|
case TK_DOTDOT: emitOpcode(compiler, OP_RANGE); break;
|
|
|
|
case TK_PERCENT: EMIT_BINARY_OP_INPLACE(OP_MOD); break;
|
|
|
|
case TK_PLUS: EMIT_BINARY_OP_INPLACE(OP_ADD); break;
|
|
|
|
case TK_MINUS: EMIT_BINARY_OP_INPLACE(OP_SUBTRACT); break;
|
|
|
|
case TK_STAR: EMIT_BINARY_OP_INPLACE(OP_MULTIPLY); break;
|
|
|
|
case TK_FSLASH: EMIT_BINARY_OP_INPLACE(OP_DIVIDE); break;
|
|
|
|
case TK_STARSTAR: EMIT_BINARY_OP_INPLACE(OP_EXPONENT); break;
|
|
|
|
case TK_AMP: EMIT_BINARY_OP_INPLACE(OP_BIT_AND); break;
|
|
|
|
case TK_PIPE: EMIT_BINARY_OP_INPLACE(OP_BIT_OR); break;
|
|
|
|
case TK_CARET: EMIT_BINARY_OP_INPLACE(OP_BIT_XOR); break;
|
|
|
|
case TK_SRIGHT: EMIT_BINARY_OP_INPLACE(OP_BIT_RSHIFT); break;
|
|
|
|
case TK_SLEFT: EMIT_BINARY_OP_INPLACE(OP_BIT_LSHIFT); break;
|
2022-04-29 02:33:20 +08:00
|
|
|
#undef EMIT_BINARY_OP_INPLACE
|
|
|
|
|
|
|
|
case TK_GT: emitOpcode(compiler, OP_GT); break;
|
|
|
|
case TK_LT: emitOpcode(compiler, OP_LT); break;
|
|
|
|
case TK_EQEQ: emitOpcode(compiler, OP_EQEQ); break;
|
|
|
|
case TK_NOTEQ: emitOpcode(compiler, OP_NOTEQ); break;
|
|
|
|
case TK_GTEQ: emitOpcode(compiler, OP_GTEQ); break;
|
|
|
|
case TK_LTEQ: emitOpcode(compiler, OP_LTEQ); break;
|
|
|
|
case TK_IN: emitOpcode(compiler, OP_IN); break;
|
|
|
|
case TK_IS: emitOpcode(compiler, OP_IS); break;
|
2021-02-12 01:35:43 +08:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprUnaryOp(Compiler* compiler) {
|
2022-04-07 11:28:51 +08:00
|
|
|
TokenType op = compiler->parser.previous.type;
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
parsePrecedence(compiler, (Precedence)(PREC_UNARY + 1));
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case TK_TILD: emitOpcode(compiler, OP_BIT_NOT); break;
|
2022-04-29 02:33:20 +08:00
|
|
|
case TK_PLUS: emitOpcode(compiler, OP_POSITIVE); break;
|
2021-02-12 01:35:43 +08:00
|
|
|
case TK_MINUS: emitOpcode(compiler, OP_NEGATIVE); break;
|
|
|
|
case TK_NOT: emitOpcode(compiler, OP_NOT); break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprGrouping(Compiler* compiler) {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-05-22 21:27:40 +08:00
|
|
|
consume(compiler, TK_RPARAN, "Expected ')' after expression.");
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprList(Compiler* compiler) {
|
2021-02-13 01:40:19 +08:00
|
|
|
|
|
|
|
emitOpcode(compiler, OP_PUSH_LIST);
|
|
|
|
int size_index = emitShort(compiler, 0);
|
|
|
|
|
|
|
|
int size = 0;
|
|
|
|
do {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
if (peek(compiler) == TK_RBRACKET) break;
|
2021-02-13 01:40:19 +08:00
|
|
|
|
|
|
|
compileExpression(compiler);
|
|
|
|
emitOpcode(compiler, OP_LIST_APPEND);
|
|
|
|
size++;
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
} while (match(compiler, TK_COMMA));
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
consume(compiler, TK_RBRACKET, "Expected ']' after list elements.");
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
patchListSize(compiler, size_index, size);
|
2021-02-13 01:40:19 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprMap(Compiler* compiler) {
|
2021-05-06 13:00:02 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_MAP);
|
|
|
|
|
|
|
|
do {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
if (peek(compiler) == TK_RBRACE) break;
|
2021-05-06 13:00:02 +08:00
|
|
|
|
|
|
|
compileExpression(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_COLLON, "Expected ':' after map's key.");
|
2021-05-06 13:00:02 +08:00
|
|
|
compileExpression(compiler);
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_MAP_INSERT);
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
} while (match(compiler, TK_COMMA));
|
2021-05-06 13:00:02 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
consume(compiler, TK_RBRACE, "Expected '}' after map elements.");
|
2021-05-06 13:00:02 +08:00
|
|
|
}
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-21 09:29:47 +08:00
|
|
|
static void exprCall(Compiler* compiler) {
|
|
|
|
_compileCall(compiler, OP_CALL, -1);
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprAttrib(Compiler* compiler) {
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_NAME, "Expected an attribute name after '.'.");
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* name = compiler->parser.previous.start;
|
|
|
|
int length = compiler->parser.previous.length;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Store the name in module's names buffer.
|
2022-04-17 09:17:27 +08:00
|
|
|
int index = 0;
|
|
|
|
moduleAddString(compiler->module, compiler->parser.vm,
|
|
|
|
name, length, &index);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-21 09:29:47 +08:00
|
|
|
// Check if it's a method call.
|
|
|
|
if (match(compiler, TK_LPARAN)) {
|
|
|
|
_compileCall(compiler, OP_METHOD_CALL, index);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-07 13:48:06 +08:00
|
|
|
// Check if it's a method call without paranthese.
|
|
|
|
if (_compileOptionalParanCall(compiler, index)) return;
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
if (compiler->l_value && matchAssignment(compiler)) {
|
2022-04-13 10:23:54 +08:00
|
|
|
TokenType assignment = compiler->parser.previous.type;
|
2021-06-20 08:49:35 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-16 02:51:00 +08:00
|
|
|
|
|
|
|
if (assignment != TK_EQ) {
|
2021-05-10 03:00:59 +08:00
|
|
|
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
2021-02-16 02:51:00 +08:00
|
|
|
emitShort(compiler, index);
|
|
|
|
compileExpression(compiler);
|
2022-04-13 10:23:54 +08:00
|
|
|
emitAssignedOp(compiler, assignment);
|
2021-02-16 02:51:00 +08:00
|
|
|
} else {
|
|
|
|
compileExpression(compiler);
|
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
emitOpcode(compiler, OP_SET_ATTRIB);
|
|
|
|
emitShort(compiler, index);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_GET_ATTRIB);
|
|
|
|
emitShort(compiler, index);
|
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprSubscript(Compiler* compiler) {
|
2021-02-16 02:51:00 +08:00
|
|
|
compileExpression(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_RBRACKET, "Expected ']' after subscription ends.");
|
2021-02-16 02:51:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
if (compiler->l_value && matchAssignment(compiler)) {
|
2022-04-13 10:23:54 +08:00
|
|
|
TokenType assignment = compiler->parser.previous.type;
|
2021-06-20 08:49:35 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-16 02:51:00 +08:00
|
|
|
|
|
|
|
if (assignment != TK_EQ) {
|
2021-05-11 14:38:23 +08:00
|
|
|
emitOpcode(compiler, OP_GET_SUBSCRIPT_KEEP);
|
2021-02-16 02:51:00 +08:00
|
|
|
compileExpression(compiler);
|
2022-04-13 10:23:54 +08:00
|
|
|
emitAssignedOp(compiler, assignment);
|
2021-02-16 02:51:00 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
compileExpression(compiler);
|
|
|
|
}
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_SET_SUBSCRIPT);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_GET_SUBSCRIPT);
|
|
|
|
}
|
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
static void exprValue(Compiler* compiler) {
|
2022-04-07 11:28:51 +08:00
|
|
|
TokenType op = compiler->parser.previous.type;
|
2021-02-12 01:35:43 +08:00
|
|
|
switch (op) {
|
2021-06-13 04:17:44 +08:00
|
|
|
case TK_NULL: emitOpcode(compiler, OP_PUSH_NULL); break;
|
|
|
|
case TK_TRUE: emitOpcode(compiler, OP_PUSH_TRUE); break;
|
|
|
|
case TK_FALSE: emitOpcode(compiler, OP_PUSH_FALSE); break;
|
2021-02-12 01:35:43 +08:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
}
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
static void exprSelf(Compiler* compiler) {
|
|
|
|
|
|
|
|
if (compiler->func->type == FUNC_CONSTRUCTOR ||
|
|
|
|
compiler->func->type == FUNC_METHOD) {
|
|
|
|
emitOpcode(compiler, OP_PUSH_SELF);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reach here 'self' is used in either non method or a closure
|
|
|
|
// inside a method.
|
|
|
|
|
|
|
|
if (!compiler->parser.parsing_class) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"Invalid use of 'self'.");
|
2022-04-21 19:53:03 +08:00
|
|
|
} else {
|
|
|
|
// FIXME:
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"TODO: Closures cannot capture 'self' for now.");
|
2022-04-21 19:53:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-01 21:12:13 +08:00
|
|
|
static void exprSuper(Compiler* compiler) {
|
|
|
|
|
|
|
|
if (compiler->func->type != FUNC_CONSTRUCTOR &&
|
|
|
|
compiler->func->type != FUNC_METHOD) {
|
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"Invalid use of 'super'.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(compiler->func->ptr != NULL, OOPS);
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
const char* name = compiler->func->ptr->name;
|
|
|
|
int name_length = -1;
|
|
|
|
|
|
|
|
if (!match(compiler, TK_LPARAN)) { // super.method().
|
|
|
|
consume(compiler, TK_DOT, "Invalid use of 'super'.");
|
|
|
|
|
|
|
|
consume(compiler, TK_NAME, "Expected a method name after 'super'.");
|
|
|
|
name = compiler->parser.previous.start;
|
|
|
|
name_length = compiler->parser.previous.length;
|
|
|
|
|
|
|
|
consume(compiler, TK_LPARAN, "Expected symbol '('.");
|
|
|
|
|
|
|
|
} else { // super().
|
|
|
|
name_length = (int)strlen(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_PUSH_SELF);
|
|
|
|
moduleAddString(compiler->module, compiler->parser.vm,
|
|
|
|
name, name_length, &index);
|
|
|
|
_compileCall(compiler, OP_SUPER_CALL, index);
|
|
|
|
}
|
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
static void parsePrecedence(Compiler* compiler, Precedence precedence) {
|
2022-04-22 20:21:17 +08:00
|
|
|
lexToken(compiler);
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
GrammarFn prefix = getRule(compiler->parser.previous.type)->prefix;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
|
|
|
if (prefix == NULL) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Expected an expression.");
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-08 18:02:51 +08:00
|
|
|
// Make a "backup" of the l value before parsing next operators to
|
|
|
|
// reset once it done.
|
|
|
|
bool l_value = compiler->l_value;
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
compiler->l_value = precedence <= PREC_LOWEST;
|
|
|
|
prefix(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-04 23:07:29 +08:00
|
|
|
// The above expression cannot be a call '(', since call is an infix
|
|
|
|
// operator. But could be true (ex: x = f()). we set is_last_call to false
|
|
|
|
// here and if the next infix operator is call this will be set to true
|
|
|
|
// once the call expression is parsed.
|
|
|
|
compiler->is_last_call = false;
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
while (getRule(compiler->parser.current.type)->precedence >= precedence) {
|
2022-04-22 20:21:17 +08:00
|
|
|
lexToken(compiler);
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
2022-04-04 23:07:29 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
TokenType op = compiler->parser.previous.type;
|
2022-04-04 23:07:29 +08:00
|
|
|
GrammarFn infix = getRule(op)->infix;
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
infix(compiler);
|
2022-04-04 23:07:29 +08:00
|
|
|
|
|
|
|
// TK_LPARAN '(' as infix is the call operator.
|
|
|
|
compiler->is_last_call = (op == TK_LPARAN);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2022-05-08 18:02:51 +08:00
|
|
|
|
|
|
|
compiler->l_value = l_value;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* COMPILING */
|
|
|
|
/*****************************************************************************/
|
2021-02-07 15:40:00 +08:00
|
|
|
|
|
|
|
// Add a variable and return it's index to the context. Assumes that the
|
|
|
|
// variable name is unique and not defined before in the current scope.
|
|
|
|
static int compilerAddVariable(Compiler* compiler, const char* name,
|
2021-06-08 00:56:56 +08:00
|
|
|
uint32_t length, int line) {
|
2021-05-19 02:59:09 +08:00
|
|
|
|
|
|
|
// TODO: should I validate the name for pre-defined, etc?
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
// Check if maximum variable count is reached.
|
|
|
|
bool max_vars_reached = false;
|
2021-06-08 00:56:56 +08:00
|
|
|
const char* var_type = ""; // For max variables reached error message.
|
2021-06-04 22:55:06 +08:00
|
|
|
if (compiler->scope_depth == DEPTH_GLOBAL) {
|
2022-04-11 16:04:22 +08:00
|
|
|
if (compiler->module->globals.count >= MAX_VARIABLES) {
|
2021-06-04 22:55:06 +08:00
|
|
|
max_vars_reached = true;
|
2021-06-14 02:41:13 +08:00
|
|
|
var_type = "globals";
|
2021-06-04 22:55:06 +08:00
|
|
|
}
|
|
|
|
} else {
|
2022-04-12 18:30:42 +08:00
|
|
|
if (compiler->func->local_count >= MAX_VARIABLES) {
|
2021-06-04 22:55:06 +08:00
|
|
|
max_vars_reached = true;
|
2021-06-14 02:41:13 +08:00
|
|
|
var_type = "locals";
|
2021-06-04 22:55:06 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (max_vars_reached) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"A module should contain at most %d %s.", MAX_VARIABLES, var_type);
|
2021-05-20 22:05:57 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
// Add the variable and return it's index.
|
|
|
|
|
|
|
|
if (compiler->scope_depth == DEPTH_GLOBAL) {
|
2022-04-11 16:04:22 +08:00
|
|
|
return (int)moduleAddGlobal(compiler->parser.vm, compiler->module,
|
2021-06-20 08:49:35 +08:00
|
|
|
name, length, VAR_NULL);
|
2021-06-04 22:55:06 +08:00
|
|
|
} else {
|
2022-04-12 18:30:42 +08:00
|
|
|
Local* local = &compiler->func->locals[compiler->func->local_count];
|
2021-06-04 22:55:06 +08:00
|
|
|
local->name = name;
|
|
|
|
local->length = length;
|
|
|
|
local->depth = compiler->scope_depth;
|
2022-04-13 08:34:14 +08:00
|
|
|
local->is_upvalue = false;
|
2021-06-04 22:55:06 +08:00
|
|
|
local->line = line;
|
2022-04-12 18:30:42 +08:00
|
|
|
return compiler->func->local_count++;
|
2021-05-19 02:59:09 +08:00
|
|
|
}
|
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
UNREACHABLE();
|
2022-04-15 20:35:15 +08:00
|
|
|
return -1;
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
static void compilerAddForward(Compiler* compiler, int instruction, Fn* fn,
|
2022-04-22 20:21:17 +08:00
|
|
|
Token* tkname) {
|
2022-04-07 11:28:51 +08:00
|
|
|
if (compiler->parser.forwards_count == MAX_FORWARD_NAMES) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, *tkname, "A module should contain at most %d "
|
|
|
|
"implicit forward function declarations.", MAX_FORWARD_NAMES);
|
2021-05-20 22:05:57 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
ForwardName* forward = &compiler->parser.forwards[
|
|
|
|
compiler->parser.forwards_count++];
|
2021-05-20 22:05:57 +08:00
|
|
|
forward->instruction = instruction;
|
|
|
|
forward->func = fn;
|
2022-04-22 20:21:17 +08:00
|
|
|
forward->tkname = *tkname;
|
2021-05-20 22:05:57 +08:00
|
|
|
}
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Add a literal constant to module literals and return it's index.
|
2021-02-09 16:21:10 +08:00
|
|
|
static int compilerAddConstant(Compiler* compiler, Var value) {
|
2022-04-11 16:04:22 +08:00
|
|
|
pkVarBuffer* constants = &compiler->module->constants;
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
uint32_t index = moduleAddConstant(compiler->parser.vm,
|
|
|
|
compiler->module, value);
|
2022-04-15 12:19:47 +08:00
|
|
|
checkMaxConstantsReached(compiler, index);
|
2022-04-10 11:07:44 +08:00
|
|
|
return (int)index;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enters inside a block.
|
|
|
|
static void compilerEnterBlock(Compiler* compiler) {
|
2021-02-12 01:35:43 +08:00
|
|
|
compiler->scope_depth++;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2021-06-14 02:41:13 +08:00
|
|
|
// Change the stack size by the [num], if it's positive, the stack will
|
|
|
|
// grow otherwise it'll shrink.
|
|
|
|
static void compilerChangeStack(Compiler* compiler, int num) {
|
2022-04-12 18:30:42 +08:00
|
|
|
compiler->func->stack_size += num;
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2022-04-03 19:29:03 +08:00
|
|
|
// If the compiler has error (such as undefined name), that will not popped
|
2021-06-14 02:41:13 +08:00
|
|
|
// because of the semantic error but it'll be popped once the expression
|
2022-04-03 19:29:03 +08:00
|
|
|
// parsing is done. So it's possible for negative size in error.
|
2022-04-12 18:30:42 +08:00
|
|
|
ASSERT(compiler->parser.has_errors || compiler->func->stack_size >= 0, OOPS);
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
if (compiler->func->stack_size > _FN->stack_size) {
|
|
|
|
_FN->stack_size = compiler->func->stack_size;
|
2021-06-14 02:41:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write instruction to pop all the locals at the current [depth] or higher,
|
|
|
|
// but it won't change the stack size of locals count because this function
|
|
|
|
// is called by break/continue statements at the middle of a scope, so we need
|
|
|
|
// those locals till the scope ends. This will returns the number of locals
|
|
|
|
// that were popped.
|
2021-06-02 17:33:29 +08:00
|
|
|
static int compilerPopLocals(Compiler* compiler, int depth) {
|
2021-05-13 17:10:57 +08:00
|
|
|
ASSERT(depth > (int)DEPTH_GLOBAL, "Cannot pop global variables.");
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-12 18:30:42 +08:00
|
|
|
int local = compiler->func->local_count - 1;
|
|
|
|
while (local >= 0 && compiler->func->locals[local].depth >= depth) {
|
2021-06-14 02:41:13 +08:00
|
|
|
|
|
|
|
// Note: Do not use emitOpcode(compiler, OP_POP);
|
|
|
|
// Because this function is called at the middle of a scope (break,
|
|
|
|
// continue). So we need the pop instruction here but we still need the
|
|
|
|
// locals to continue parsing the next statements in the scope. They'll be
|
|
|
|
// popped once the scope is ended.
|
2022-04-13 17:01:57 +08:00
|
|
|
|
|
|
|
if (compiler->func->locals[local].is_upvalue) {
|
|
|
|
emitByte(compiler, OP_CLOSE_UPVALUE);
|
|
|
|
} else {
|
|
|
|
emitByte(compiler, OP_POP);
|
|
|
|
}
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2021-05-13 17:10:57 +08:00
|
|
|
local--;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2022-04-12 18:30:42 +08:00
|
|
|
return (compiler->func->local_count - 1) - local;
|
2021-05-13 17:10:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exits a block.
|
|
|
|
static void compilerExitBlock(Compiler* compiler) {
|
|
|
|
ASSERT(compiler->scope_depth > (int)DEPTH_GLOBAL, "Cannot exit toplevel.");
|
|
|
|
|
|
|
|
// Discard all the locals at the current scope.
|
2021-06-02 17:33:29 +08:00
|
|
|
int popped = compilerPopLocals(compiler, compiler->scope_depth);
|
2022-04-12 18:30:42 +08:00
|
|
|
compiler->func->local_count -= popped;
|
|
|
|
compiler->func->stack_size -= popped;
|
2021-02-12 01:35:43 +08:00
|
|
|
compiler->scope_depth--;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2021-06-20 23:28:31 +08:00
|
|
|
static void compilerPushFunc(Compiler* compiler, Func* fn,
|
2022-04-21 19:53:03 +08:00
|
|
|
Function* func, FuncType type) {
|
|
|
|
fn->type = type;
|
2021-06-20 23:28:31 +08:00
|
|
|
fn->outer_func = compiler->func;
|
2022-04-12 18:30:42 +08:00
|
|
|
fn->local_count = 0;
|
|
|
|
fn->stack_size = 0;
|
2021-06-20 23:28:31 +08:00
|
|
|
fn->ptr = func;
|
|
|
|
fn->depth = compiler->scope_depth;
|
|
|
|
compiler->func = fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void compilerPopFunc(Compiler* compiler) {
|
|
|
|
compiler->func = compiler->func->outer_func;
|
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* COMPILING (EMIT BYTECODE) */
|
|
|
|
/*****************************************************************************/
|
2021-02-09 16:21:10 +08:00
|
|
|
|
|
|
|
// Emit a single byte and return it's index.
|
|
|
|
static int emitByte(Compiler* compiler, int byte) {
|
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
pkByteBufferWrite(&_FN->opcodes, compiler->parser.vm,
|
2021-02-09 16:21:10 +08:00
|
|
|
(uint8_t)byte);
|
2022-04-07 11:28:51 +08:00
|
|
|
pkUintBufferWrite(&_FN->oplines, compiler->parser.vm,
|
|
|
|
compiler->parser.previous.line);
|
2021-02-13 21:57:59 +08:00
|
|
|
return (int)_FN->opcodes.count - 1;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit 2 bytes argument as big indian. return it's starting index.
|
|
|
|
static int emitShort(Compiler* compiler, int arg) {
|
2021-02-12 01:35:43 +08:00
|
|
|
emitByte(compiler, (arg >> 8) & 0xff);
|
|
|
|
return emitByte(compiler, arg & 0xff) - 1;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emits an instruction and update stack size (variable stack size opcodes
|
|
|
|
// should be handled).
|
|
|
|
static void emitOpcode(Compiler* compiler, Opcode opcode) {
|
2021-02-12 01:35:43 +08:00
|
|
|
emitByte(compiler, (int)opcode);
|
2022-04-03 19:29:03 +08:00
|
|
|
// If the opcode is OP_CALL the compiler should change the stack size
|
|
|
|
// manually because we don't know that here.
|
2021-06-14 02:41:13 +08:00
|
|
|
compilerChangeStack(compiler, opcode_info[opcode].stack);
|
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-06-14 02:41:13 +08:00
|
|
|
// Jump back to the start of the loop.
|
|
|
|
static void emitLoopJump(Compiler* compiler) {
|
|
|
|
emitOpcode(compiler, OP_LOOP);
|
|
|
|
int offset = (int)_FN->opcodes.count - compiler->loop->start + 2;
|
|
|
|
emitShort(compiler, offset);
|
|
|
|
}
|
|
|
|
|
2022-04-13 10:23:54 +08:00
|
|
|
static void emitAssignedOp(Compiler* compiler, TokenType assignment) {
|
2022-04-29 02:33:20 +08:00
|
|
|
// Emits the opcode and 1 (means true) as inplace operation.
|
|
|
|
#define EMIT_BINARY_OP_INPLACE(opcode)\
|
|
|
|
do { emitOpcode(compiler, opcode); emitByte(compiler, 1); } while (false)
|
|
|
|
|
2021-06-14 02:41:13 +08:00
|
|
|
switch (assignment) {
|
2022-04-29 02:33:20 +08:00
|
|
|
case TK_PLUSEQ: EMIT_BINARY_OP_INPLACE(OP_ADD); break;
|
|
|
|
case TK_MINUSEQ: EMIT_BINARY_OP_INPLACE(OP_SUBTRACT); break;
|
|
|
|
case TK_STAREQ: EMIT_BINARY_OP_INPLACE(OP_MULTIPLY); break;
|
|
|
|
case TK_DIVEQ: EMIT_BINARY_OP_INPLACE(OP_DIVIDE); break;
|
|
|
|
case TK_MODEQ: EMIT_BINARY_OP_INPLACE(OP_MOD); break;
|
2022-05-08 18:02:51 +08:00
|
|
|
case TK_POWEQ: EMIT_BINARY_OP_INPLACE(OP_EXPONENT); break;
|
2022-04-29 02:33:20 +08:00
|
|
|
case TK_ANDEQ: EMIT_BINARY_OP_INPLACE(OP_BIT_AND); break;
|
|
|
|
case TK_OREQ: EMIT_BINARY_OP_INPLACE(OP_BIT_OR); break;
|
|
|
|
case TK_XOREQ: EMIT_BINARY_OP_INPLACE(OP_BIT_XOR); break;
|
|
|
|
case TK_SRIGHTEQ: EMIT_BINARY_OP_INPLACE(OP_BIT_RSHIFT); break;
|
|
|
|
case TK_SLEFTEQ: EMIT_BINARY_OP_INPLACE(OP_BIT_LSHIFT); break;
|
2021-06-14 02:41:13 +08:00
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
2022-04-29 02:33:20 +08:00
|
|
|
#undef EMIT_BINARY_OP_INPLACE
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
static void emitFunctionEnd(Compiler* compiler) {
|
|
|
|
|
2022-03-31 01:50:44 +08:00
|
|
|
// Don't use emitOpcode(compiler, OP_RETURN); Because it'll reduce the stack
|
2022-04-03 19:29:03 +08:00
|
|
|
// size by -1, (return value will be popped). This return is implictly added
|
|
|
|
// by the compiler.
|
|
|
|
// Since we're returning from the end of the function, there'll always be a
|
|
|
|
// null value at the base of the current call frame the reserved return value
|
|
|
|
// slot.
|
2021-06-16 02:54:30 +08:00
|
|
|
emitByte(compiler, OP_RETURN);
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_END);
|
|
|
|
}
|
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
// Update the jump offset.
|
2021-02-09 16:21:10 +08:00
|
|
|
static void patchJump(Compiler* compiler, int addr_index) {
|
2021-06-02 17:33:29 +08:00
|
|
|
int offset = (int)_FN->opcodes.count - (addr_index + 2 /*bytes index*/);
|
2021-05-16 01:57:34 +08:00
|
|
|
ASSERT(offset < MAX_JUMP, "Too large address offset to jump to.");
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-05-16 01:57:34 +08:00
|
|
|
_FN->opcodes.data[addr_index] = (offset >> 8) & 0xff;
|
|
|
|
_FN->opcodes.data[addr_index + 1] = offset & 0xff;
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2022-04-05 10:55:32 +08:00
|
|
|
// Update the size value for OP_PUSH_LIST instruction.
|
|
|
|
static void patchListSize(Compiler* compiler, int size_index, int size) {
|
|
|
|
_FN->opcodes.data[size_index] = (size >> 8) & 0xff;
|
|
|
|
_FN->opcodes.data[size_index + 1] = size & 0xff;
|
|
|
|
}
|
|
|
|
|
2021-06-04 09:28:42 +08:00
|
|
|
static void patchForward(Compiler* compiler, Fn* fn, int index, int name) {
|
2021-06-04 22:55:06 +08:00
|
|
|
fn->opcodes.data[index] = name & 0xff;
|
2021-05-20 22:05:57 +08:00
|
|
|
}
|
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* COMPILING (PARSE TOPLEVEL) */
|
|
|
|
/*****************************************************************************/
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-16 02:51:00 +08:00
|
|
|
typedef enum {
|
|
|
|
BLOCK_FUNC,
|
|
|
|
BLOCK_LOOP,
|
|
|
|
BLOCK_IF,
|
|
|
|
BLOCK_ELSE,
|
|
|
|
} BlockType;
|
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
static void compileStatement(Compiler* compiler);
|
2021-02-16 02:51:00 +08:00
|
|
|
static void compileBlockBody(Compiler* compiler, BlockType type);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Compile a class and return it's index in the module's types buffer.
|
2022-04-21 19:53:03 +08:00
|
|
|
static int compileClass(Compiler* compiler) {
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-04-20 16:24:45 +08:00
|
|
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
|
|
|
|
2021-06-20 23:28:31 +08:00
|
|
|
// Consume the name of the type.
|
2022-04-21 19:53:03 +08:00
|
|
|
consume(compiler, TK_NAME, "Expected a class name.");
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* name = compiler->parser.previous.start;
|
|
|
|
int name_len = compiler->parser.previous.length;
|
2022-04-20 16:24:45 +08:00
|
|
|
int name_line = compiler->parser.previous.line;
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-03-31 02:13:18 +08:00
|
|
|
// Create a new class.
|
2022-04-20 16:24:45 +08:00
|
|
|
int cls_index;
|
2022-04-20 18:05:33 +08:00
|
|
|
PKVM* _vm = compiler->parser.vm;
|
|
|
|
Class* cls = newClass(_vm, name, name_len,
|
|
|
|
_vm->builtin_classes[PK_OBJECT], compiler->module,
|
|
|
|
NULL, &cls_index);
|
2022-04-21 19:53:03 +08:00
|
|
|
vmPushTempRef(_vm, &cls->_super); // cls.
|
|
|
|
compiler->parser.parsing_class = true;
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-04-15 12:19:47 +08:00
|
|
|
checkMaxConstantsReached(compiler, cls_index);
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-04-27 00:27:35 +08:00
|
|
|
if (match(compiler, TK_IS)) {
|
|
|
|
consume(compiler, TK_NAME, "Expected a class name to inherit.");
|
|
|
|
if (!compiler->parser.has_syntax_error) {
|
|
|
|
exprName(compiler); // Push the super class on the stack.
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Implicitly inherit from 'Object' class.
|
|
|
|
emitPushValue(compiler, NAME_BUILTIN_TY, (int)PK_OBJECT);
|
|
|
|
}
|
|
|
|
|
|
|
|
emitOpcode(compiler, OP_CREATE_CLASS);
|
2022-04-26 18:23:30 +08:00
|
|
|
emitShort(compiler, cls_index);
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
skipNewLines(compiler);
|
2022-04-27 00:27:35 +08:00
|
|
|
while (!compiler->parser.has_syntax_error && !match(compiler, TK_END)) {
|
2022-04-25 19:23:07 +08:00
|
|
|
|
|
|
|
if (match(compiler, TK_EOF)) {
|
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Unexpected EOF while parsing class.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// At the top level the stack size should be 1 -- the class, before and
|
|
|
|
// after compiling the class.
|
2022-04-21 19:53:03 +08:00
|
|
|
ASSERT(compiler->parser.has_errors ||
|
2022-04-26 18:23:30 +08:00
|
|
|
compiler->func->stack_size == 1, OOPS);
|
2022-04-21 19:53:03 +08:00
|
|
|
|
|
|
|
consume(compiler, TK_DEF, "Expected method definition.");
|
2022-04-22 20:21:17 +08:00
|
|
|
if (compiler->parser.has_syntax_error) break;
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
compileFunction(compiler, FUNC_METHOD);
|
2022-04-22 20:21:17 +08:00
|
|
|
if (compiler->parser.has_syntax_error) break;
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// At the top level the stack size should be 1 -- the class, before and
|
|
|
|
// after compiling the class.
|
2022-04-21 19:53:03 +08:00
|
|
|
ASSERT(compiler->parser.has_errors ||
|
2022-04-26 18:23:30 +08:00
|
|
|
compiler->func->stack_size == 1, OOPS);
|
2022-04-21 19:53:03 +08:00
|
|
|
|
|
|
|
skipNewLines(compiler);
|
|
|
|
}
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
int global_index = compilerAddVariable(compiler, name, name_len, name_line);
|
|
|
|
emitStoreValue(compiler, NAME_GLOBAL_VAR, global_index);
|
|
|
|
emitOpcode(compiler, OP_POP); // Pop the class.
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
compiler->parser.parsing_class = false;
|
|
|
|
vmPopTempRef(_vm); // cls.
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
return cls_index;
|
2021-06-20 23:28:31 +08:00
|
|
|
}
|
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
// Match operator mathod definition. This will match the operator overloading
|
|
|
|
// method syntax of ruby.
|
|
|
|
static bool matchOperatorMethod(Compiler* compiler,
|
|
|
|
const char** name, int* length, int* argc) {
|
|
|
|
ASSERT((name != NULL) && (length != NULL) && (argc != NULL), OOPS);
|
|
|
|
#define _RET(_name, _argc) \
|
|
|
|
do { \
|
|
|
|
*name = _name; *length = (int)strlen(_name); \
|
|
|
|
*argc = _argc; \
|
|
|
|
return true; \
|
|
|
|
} while (false)
|
|
|
|
|
|
|
|
if (match(compiler, TK_PLUS)) {
|
|
|
|
if (match(compiler, TK_SELF)) _RET("+self", 0);
|
|
|
|
else _RET("+", 1);
|
|
|
|
}
|
|
|
|
if (match(compiler, TK_MINUS)) {
|
|
|
|
if (match(compiler, TK_SELF)) _RET("-self", 0);
|
|
|
|
else _RET("-", 1);
|
|
|
|
}
|
|
|
|
if (match(compiler, TK_TILD)){
|
|
|
|
if (match(compiler, TK_SELF)) _RET("~self", 0);
|
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Expected keyword self for unary operator definition.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (match(compiler, TK_NOT)) {
|
|
|
|
if (match(compiler, TK_SELF)) _RET("!self", 0);
|
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Expected keyword self for unary operator definition.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match(compiler, TK_PLUSEQ)) _RET("+=", 1);
|
|
|
|
if (match(compiler, TK_MINUSEQ)) _RET("-=", 1);
|
|
|
|
if (match(compiler, TK_STAR)) _RET("*", 1);
|
|
|
|
if (match(compiler, TK_STAREQ)) _RET("*=", 1);
|
|
|
|
if (match(compiler, TK_FSLASH)) _RET("/", 1);
|
2022-05-08 18:02:51 +08:00
|
|
|
if (match(compiler, TK_STARSTAR)) _RET("**", 1);
|
2022-04-29 02:33:20 +08:00
|
|
|
if (match(compiler, TK_DIVEQ)) _RET("/=", 1);
|
|
|
|
if (match(compiler, TK_PERCENT)) _RET("%", 1);
|
|
|
|
if (match(compiler, TK_MODEQ)) _RET("%=", 1);
|
2022-05-08 18:02:51 +08:00
|
|
|
if (match(compiler, TK_POWEQ)) _RET("**=", 1);
|
2022-04-29 02:33:20 +08:00
|
|
|
if (match(compiler, TK_AMP)) _RET("&", 1);
|
|
|
|
if (match(compiler, TK_ANDEQ)) _RET("&=", 1);
|
|
|
|
if (match(compiler, TK_PIPE)) _RET("|", 1);
|
|
|
|
if (match(compiler, TK_OREQ)) _RET("|=", 1);
|
|
|
|
if (match(compiler, TK_CARET)) _RET("^", 1);
|
|
|
|
if (match(compiler, TK_XOREQ)) _RET("^=", 1);
|
|
|
|
if (match(compiler, TK_SLEFT)) _RET("<<", 1);
|
|
|
|
if (match(compiler, TK_SLEFTEQ)) _RET("<<=", 1);
|
|
|
|
if (match(compiler, TK_SRIGHT)) _RET(">>", 1);
|
|
|
|
if (match(compiler, TK_SRIGHTEQ)) _RET(">>=", 1);
|
|
|
|
if (match(compiler, TK_EQEQ)) _RET("==", 1);
|
|
|
|
if (match(compiler, TK_GT)) _RET(">", 1);
|
|
|
|
if (match(compiler, TK_LT)) _RET("<", 1);
|
|
|
|
if (match(compiler, TK_DOTDOT)) _RET("..", 1);
|
|
|
|
if (match(compiler, TK_IN)) _RET("in", 1);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
#undef _RET
|
|
|
|
}
|
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// Compile a function, if it's a literal function after this call a closure of
|
|
|
|
// the function will be at the stack top, toplevel functions will be assigned
|
|
|
|
// to a global variable and popped, and methods will be bind to the class and
|
|
|
|
// popped.
|
|
|
|
static void compileFunction(Compiler* compiler, FuncType fn_type) {
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
const char* name;
|
2021-02-16 02:51:00 +08:00
|
|
|
int name_length;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
// If it's an operator method the bellow value will set to a positive value
|
|
|
|
// (the argc of the method) it requires to throw a compile time error.
|
|
|
|
int operator_argc = -2;
|
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
if (fn_type != FUNC_LITERAL) {
|
2022-04-29 02:33:20 +08:00
|
|
|
|
|
|
|
if (match(compiler, TK_NAME)) {
|
|
|
|
name = compiler->parser.previous.start;
|
|
|
|
name_length = compiler->parser.previous.length;
|
|
|
|
|
|
|
|
} else if (fn_type == FUNC_METHOD &&
|
|
|
|
matchOperatorMethod(compiler, &name, &name_length, &operator_argc)) {
|
|
|
|
|
|
|
|
// Check if any error has been set by operator definition.
|
|
|
|
} else if (!compiler->parser.has_syntax_error) {
|
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Expected a function name.");
|
|
|
|
}
|
2021-02-13 21:57:59 +08:00
|
|
|
|
|
|
|
} else {
|
2021-06-07 13:54:06 +08:00
|
|
|
name = LITERAL_FN_NAME;
|
2021-02-16 02:51:00 +08:00
|
|
|
name_length = (int)strlen(name);
|
2021-02-13 21:57:59 +08:00
|
|
|
}
|
2021-06-10 07:35:14 +08:00
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
if (compiler->parser.has_syntax_error) return;
|
|
|
|
|
2022-04-10 11:07:44 +08:00
|
|
|
int fn_index;
|
2022-04-07 11:28:51 +08:00
|
|
|
Function* func = newFunction(compiler->parser.vm, name, name_length,
|
2022-04-12 04:49:09 +08:00
|
|
|
compiler->module, false, NULL, &fn_index);
|
2022-04-22 20:21:17 +08:00
|
|
|
|
2022-04-15 12:19:47 +08:00
|
|
|
checkMaxConstantsReached(compiler, fn_index);
|
2022-04-10 11:07:44 +08:00
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
// Only to be used by the toplevle function to define itself on the globals
|
|
|
|
// of the module.
|
|
|
|
int global_index = -1;
|
|
|
|
|
|
|
|
if (fn_type == FUNC_TOPLEVEL) {
|
2022-04-10 11:07:44 +08:00
|
|
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
|
|
|
int name_line = compiler->parser.previous.line;
|
2022-04-26 18:23:30 +08:00
|
|
|
global_index = compilerAddVariable(compiler, name, name_length, name_line);
|
2021-06-04 22:55:06 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
if (fn_type == FUNC_METHOD && strncmp(name, CTOR_NAME, name_length) == 0) {
|
2022-04-21 19:53:03 +08:00
|
|
|
fn_type = FUNC_CONSTRUCTOR;
|
|
|
|
}
|
|
|
|
|
2021-06-20 23:28:31 +08:00
|
|
|
Func curr_fn;
|
2022-04-21 19:53:03 +08:00
|
|
|
compilerPushFunc(compiler, &curr_fn, func, fn_type);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
int argc = 0;
|
|
|
|
compilerEnterBlock(compiler); // Parameter depth.
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Parameter list is optional.
|
2021-05-18 19:21:38 +08:00
|
|
|
if (match(compiler, TK_LPARAN) && !match(compiler, TK_RPARAN)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
do {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_NAME, "Expected a parameter name.");
|
2021-02-12 01:35:43 +08:00
|
|
|
argc++;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* param_name = compiler->parser.previous.start;
|
|
|
|
uint32_t param_len = compiler->parser.previous.length;
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-04 22:55:06 +08:00
|
|
|
// TODO: move this to a functions.
|
2021-02-12 01:35:43 +08:00
|
|
|
bool predefined = false;
|
2022-04-12 18:30:42 +08:00
|
|
|
for (int i = compiler->func->local_count - 1; i >= 0; i--) {
|
|
|
|
Local* local = &compiler->func->locals[i];
|
2021-06-04 22:55:06 +08:00
|
|
|
if (local->length == param_len &&
|
|
|
|
strncmp(local->name, param_name, param_len) == 0) {
|
2021-02-12 01:35:43 +08:00
|
|
|
predefined = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-06-04 22:55:06 +08:00
|
|
|
if (predefined) {
|
2022-04-22 20:21:17 +08:00
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"Multiple definition of a parameter.");
|
2021-06-04 22:55:06 +08:00
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compilerAddVariable(compiler, param_name, param_len,
|
2022-04-07 11:28:51 +08:00
|
|
|
compiler->parser.previous.line);
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
} while (match(compiler, TK_COMMA));
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_RPARAN, "Expected ')' after parameter list.");
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-29 02:33:20 +08:00
|
|
|
if (operator_argc >= 0 && argc != operator_argc) {
|
|
|
|
semanticError(compiler, compiler->parser.previous,
|
|
|
|
"Expected exactly %d parameters.", operator_argc);
|
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
func->arity = argc;
|
2021-06-14 02:41:13 +08:00
|
|
|
compilerChangeStack(compiler, argc);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-12 04:49:09 +08:00
|
|
|
compileBlockBody(compiler, BLOCK_FUNC);
|
2021-02-12 14:53:52 +08:00
|
|
|
|
2022-04-21 19:53:03 +08:00
|
|
|
if (fn_type == FUNC_CONSTRUCTOR) {
|
|
|
|
emitOpcode(compiler, OP_PUSH_SELF);
|
|
|
|
emitOpcode(compiler, OP_RETURN);
|
|
|
|
}
|
|
|
|
|
2022-04-12 04:49:09 +08:00
|
|
|
consume(compiler, TK_END, "Expected 'end' after function definition end.");
|
|
|
|
compilerExitBlock(compiler); // Parameter depth.
|
|
|
|
emitFunctionEnd(compiler);
|
2021-02-18 02:27:24 +08:00
|
|
|
|
2022-04-08 00:02:20 +08:00
|
|
|
#if DUMP_BYTECODE
|
2022-04-10 11:07:44 +08:00
|
|
|
// FIXME:
|
|
|
|
// Forward patch are pending so we can't dump constant value that
|
|
|
|
// needs to be patched.
|
|
|
|
//dumpFunctionCode(compiler->parser.vm, compiler->func->ptr);
|
2021-02-18 02:27:24 +08:00
|
|
|
#endif
|
2021-06-20 23:28:31 +08:00
|
|
|
|
|
|
|
compilerPopFunc(compiler);
|
2021-02-13 21:57:59 +08:00
|
|
|
|
2022-04-13 17:01:57 +08:00
|
|
|
// Note: After the above compilerPopFunc() call, now we're at the outer
|
|
|
|
// function of this function, and the bellow emit calls will write to the
|
|
|
|
// outer function. If it's a literal function, we need to push a closure
|
|
|
|
// of it on the stack.
|
2022-04-26 18:23:30 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_CLOSURE);
|
|
|
|
emitShort(compiler, fn_index);
|
|
|
|
|
|
|
|
// Capture the upvalues when the closure is created.
|
|
|
|
for (int i = 0; i < curr_fn.ptr->upvalue_count; i++) {
|
|
|
|
emitByte(compiler, (curr_fn.upvalues[i].is_immediate) ? 1 : 0);
|
|
|
|
emitByte(compiler, curr_fn.upvalues[i].index);
|
2022-04-13 17:01:57 +08:00
|
|
|
}
|
2022-04-21 19:53:03 +08:00
|
|
|
|
2022-04-26 18:23:30 +08:00
|
|
|
if (fn_type == FUNC_TOPLEVEL) {
|
|
|
|
emitStoreValue(compiler, NAME_GLOBAL_VAR, global_index);
|
|
|
|
emitOpcode(compiler, OP_POP);
|
|
|
|
|
|
|
|
} else if (fn_type == FUNC_METHOD || fn_type == FUNC_CONSTRUCTOR) {
|
|
|
|
// Bind opcode will also pop the method so, we shouldn't do it here.
|
|
|
|
emitOpcode(compiler, OP_BIND_METHOD);
|
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
}
|
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
// Finish a block body.
|
2021-02-16 02:51:00 +08:00
|
|
|
static void compileBlockBody(Compiler* compiler, BlockType type) {
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compilerEnterBlock(compiler);
|
2021-02-16 02:51:00 +08:00
|
|
|
|
2021-05-11 14:38:23 +08:00
|
|
|
if (type == BLOCK_IF) {
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeStartBlock(compiler, TK_THEN);
|
|
|
|
skipNewLines(compiler);
|
2021-05-11 14:38:23 +08:00
|
|
|
|
|
|
|
} else if (type == BLOCK_ELSE) {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-05-11 14:38:23 +08:00
|
|
|
|
|
|
|
} else if (type == BLOCK_FUNC) {
|
|
|
|
// Function body doesn't require a 'do' or 'then' delimiter to enter.
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-05-11 14:38:23 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// For/While loop block body delimiter is 'do'.
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeStartBlock(compiler, TK_DO);
|
|
|
|
skipNewLines(compiler);
|
2021-02-16 02:51:00 +08:00
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
TokenType next = peek(compiler);
|
2022-04-17 09:29:18 +08:00
|
|
|
while (!(next == TK_END || next == TK_EOF ||
|
|
|
|
((type == BLOCK_IF) && (next == TK_ELSE)))) {
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compileStatement(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
next = peek(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compilerExitBlock(compiler);
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Parse the module path syntax, emit opcode to load module at that path.
|
|
|
|
// and return the module's name token
|
|
|
|
//
|
|
|
|
// ex: import foo.bar.baz // => "foo/bar/baz" => return token 'baz'
|
|
|
|
// import .qux.lex // => "./qux/lex" => return token 'lex'
|
|
|
|
// import ^^foo.bar // => "../../foo/bar" => return token 'bar'
|
|
|
|
//
|
|
|
|
// The name start pointer and its length will be written to the parameters.
|
|
|
|
// For invalid syntax it'll set an error and return an error token.
|
|
|
|
static Token compileImportPath(Compiler* compiler) {
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2022-04-07 11:28:51 +08:00
|
|
|
PKVM* vm = compiler->parser.vm;
|
2022-05-06 10:46:40 +08:00
|
|
|
pkByteBuffer buff; // A buffer to write the path string.
|
|
|
|
pkByteBufferInit(&buff);
|
2021-05-10 03:00:59 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
if (match(compiler, TK_DOT)) {
|
|
|
|
pkByteBufferAddString(&buff, vm, "./", 2);
|
2021-05-10 03:00:59 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
} else {
|
|
|
|
// Consume parent directory syntax.
|
|
|
|
while (match(compiler, TK_CARET)) {
|
|
|
|
pkByteBufferAddString(&buff, vm, "../", 3);
|
|
|
|
}
|
2021-05-19 02:59:09 +08:00
|
|
|
}
|
2021-05-09 20:31:36 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
Token tkmodule = makeErrToken(&compiler->parser);
|
2021-05-10 03:00:59 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Consume module path.
|
|
|
|
do {
|
|
|
|
consume(compiler, TK_NAME, "Expected a module name");
|
|
|
|
if (compiler->parser.has_syntax_error) break;
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// A '.' consumed, write '/'.
|
|
|
|
if (tkmodule.type != TK_ERROR) pkByteBufferWrite(&buff, vm, (uint8_t) '/');
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
tkmodule = compiler->parser.previous;
|
|
|
|
pkByteBufferAddString(&buff, vm, tkmodule.start, tkmodule.length);
|
2021-06-07 13:54:06 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
} while (match(compiler, TK_DOT));
|
|
|
|
pkByteBufferWrite(&buff, vm, '\0');
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
if (compiler->parser.has_syntax_error) {
|
|
|
|
pkByteBufferClear(&buff, vm);
|
|
|
|
return makeErrToken(&compiler->parser);
|
2021-06-09 18:42:26 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Create constant pool entry for the path string.
|
2022-04-17 09:17:27 +08:00
|
|
|
int index = 0;
|
2022-05-06 10:46:40 +08:00
|
|
|
moduleAddString(compiler->module, compiler->parser.vm,
|
|
|
|
buff.data, buff.count - 1, &index);
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
pkByteBufferClear(&buff, vm);
|
2021-05-19 02:59:09 +08:00
|
|
|
|
|
|
|
emitOpcode(compiler, OP_IMPORT);
|
|
|
|
emitShort(compiler, index);
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
return tkmodule;
|
2021-05-19 02:59:09 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// import module1 [as alias1 [, module2 [as alias2 ...]]
|
|
|
|
void compileRegularImport(Compiler* compiler) {
|
2021-06-14 02:41:13 +08:00
|
|
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
do {
|
|
|
|
Token tkmodule = compileImportPath(compiler);
|
|
|
|
if (tkmodule.type == TK_ERROR) return; //< Syntax error. Terminate.
|
2021-06-04 22:55:06 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
if (match(compiler, TK_AS)) {
|
|
|
|
consume(compiler, TK_NAME, "Expected a name after 'as'.");
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
|
|
|
tkmodule = compiler->parser.previous;
|
|
|
|
}
|
2021-06-20 18:23:21 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// FIXME:
|
|
|
|
// Note that for compilerAddVariable for adding global doesn't create
|
|
|
|
// a new global variable if it's already exists. But it'll reuse it. So we
|
|
|
|
// don't have to check if it's exists (unlike locals) which is an
|
|
|
|
// inconsistance behavior IMO. The problem here is that compilerAddVariable
|
|
|
|
// will try to initialize the global with VAR_NULL which may not be
|
|
|
|
// accceptable in some scenarios,
|
|
|
|
int global_index = compilerAddVariable(compiler, tkmodule.start,
|
|
|
|
tkmodule.length, tkmodule.line);
|
|
|
|
|
|
|
|
emitStoreGlobal(compiler, global_index);
|
|
|
|
emitOpcode(compiler, OP_POP);
|
2021-06-20 18:23:21 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
} while (match(compiler, TK_COMMA) && (skipNewLines(compiler), true));
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Always end the import statement.
|
|
|
|
consumeEndStatement(compiler);
|
2021-05-09 20:31:36 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// from module import sym1 [as alias1 [, sym2 [as alias2 ...]]]
|
2021-05-19 02:59:09 +08:00
|
|
|
static void compileFromImport(Compiler* compiler) {
|
2021-06-14 02:41:13 +08:00
|
|
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
2021-05-10 03:00:59 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
Token tkmodule = compileImportPath(compiler);
|
|
|
|
if (tkmodule.type == TK_ERROR) return; //< Syntax error. Terminate.
|
2021-05-10 03:00:59 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// At this point the module would be on the stack before executing the next
|
2021-05-19 02:59:09 +08:00
|
|
|
// instruction.
|
|
|
|
consume(compiler, TK_IMPORT, "Expected keyword 'import'.");
|
2022-05-06 10:46:40 +08:00
|
|
|
if (compiler->parser.has_syntax_error) return;
|
2021-06-14 02:41:13 +08:00
|
|
|
|
2021-05-19 02:59:09 +08:00
|
|
|
do {
|
2022-05-06 10:46:40 +08:00
|
|
|
// Consume the symbol name to import from the module.
|
|
|
|
consume(compiler, TK_NAME, "Expected symbol to import.");
|
|
|
|
if (compiler->parser.has_syntax_error) return;
|
|
|
|
Token tkname = compiler->parser.previous;
|
2021-05-22 21:27:40 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Add the name of the symbol to the constant pool.
|
|
|
|
int name_index = 0;
|
|
|
|
moduleAddString(compiler->module, compiler->parser.vm, tkname.start,
|
|
|
|
tkname.length, &name_index);
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Don't pop the lib since it'll be used for the next entry.
|
|
|
|
emitOpcode(compiler, OP_GET_ATTRIB_KEEP);
|
|
|
|
emitShort(compiler, name_index); //< Name of the attrib.
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Check if it has an alias.
|
2021-05-19 02:59:09 +08:00
|
|
|
if (match(compiler, TK_AS)) {
|
|
|
|
// Consuming it'll update the previous token which would be the name of
|
|
|
|
// the binding variable.
|
|
|
|
consume(compiler, TK_NAME, "Expected a name after 'as'.");
|
2022-05-06 10:46:40 +08:00
|
|
|
tkname = compiler->parser.previous;
|
2021-05-19 02:59:09 +08:00
|
|
|
}
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// FIXME: See the same FIXME for compilerAddVariable()
|
|
|
|
// compileRegularImport function.
|
|
|
|
int global_index = compilerAddVariable(compiler, tkname.start,
|
|
|
|
tkname.length, tkname.line);
|
|
|
|
emitStoreGlobal(compiler, global_index);
|
|
|
|
emitOpcode(compiler, OP_POP);
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2021-06-08 00:56:56 +08:00
|
|
|
} while (match(compiler, TK_COMMA) && (skipNewLines(compiler), true));
|
2021-05-19 02:59:09 +08:00
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
// Done getting all the attributes, now pop the lib from the stack.
|
|
|
|
emitOpcode(compiler, OP_POP);
|
|
|
|
|
|
|
|
// Always end the import statement.
|
2021-05-19 02:59:09 +08:00
|
|
|
consumeEndStatement(compiler);
|
|
|
|
}
|
|
|
|
|
2021-02-09 16:21:10 +08:00
|
|
|
// Compiles an expression. An expression will result a value on top of the
|
|
|
|
// stack.
|
|
|
|
static void compileExpression(Compiler* compiler) {
|
2021-02-12 01:35:43 +08:00
|
|
|
parsePrecedence(compiler, PREC_LOWEST);
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
static void compileIfStatement(Compiler* compiler, bool else_if) {
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler); //< Condition.
|
|
|
|
emitOpcode(compiler, OP_JUMP_IF_NOT);
|
|
|
|
int ifpatch = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-16 02:51:00 +08:00
|
|
|
compileBlockBody(compiler, BLOCK_IF);
|
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
if (match(compiler, TK_ELSE)) {
|
2021-02-16 02:51:00 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
if (match(compiler, TK_IF)) { //< Compile 'else if'.
|
|
|
|
// Jump pass else.
|
|
|
|
emitOpcode(compiler, OP_JUMP);
|
|
|
|
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
// if (false) jump here.
|
|
|
|
patchJump(compiler, ifpatch);
|
2021-06-02 17:33:29 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
compilerEnterBlock(compiler);
|
|
|
|
compileIfStatement(compiler, true);
|
|
|
|
compilerExitBlock(compiler);
|
2021-06-02 17:33:29 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
patchJump(compiler, exit_jump);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
} else { //< Compile 'else'.
|
2021-02-16 02:51:00 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
// Jump pass else.
|
|
|
|
emitOpcode(compiler, OP_JUMP);
|
|
|
|
int exit_jump = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-02-16 02:51:00 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
patchJump(compiler, ifpatch);
|
|
|
|
compileBlockBody(compiler, BLOCK_ELSE);
|
|
|
|
patchJump(compiler, exit_jump);
|
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
|
|
|
patchJump(compiler, ifpatch);
|
|
|
|
}
|
2021-02-11 01:23:48 +08:00
|
|
|
|
2022-04-17 09:29:18 +08:00
|
|
|
// 'else if' will not consume the 'end' keyword as it'll be leaved to be
|
|
|
|
// consumed by it's 'if'.
|
|
|
|
if (!else_if) {
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
consume(compiler, TK_END, "Expected 'end' after statement end.");
|
2021-02-16 02:51:00 +08:00
|
|
|
}
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void compileWhileStatement(Compiler* compiler) {
|
2021-02-12 01:35:43 +08:00
|
|
|
Loop loop;
|
2021-02-13 21:57:59 +08:00
|
|
|
loop.start = (int)_FN->opcodes.count;
|
2021-02-12 01:35:43 +08:00
|
|
|
loop.patch_count = 0;
|
|
|
|
loop.outer_loop = compiler->loop;
|
2021-05-13 17:10:57 +08:00
|
|
|
loop.depth = compiler->scope_depth;
|
2021-02-12 01:35:43 +08:00
|
|
|
compiler->loop = &loop;
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler); //< Condition.
|
|
|
|
emitOpcode(compiler, OP_JUMP_IF_NOT);
|
2021-02-18 02:27:24 +08:00
|
|
|
int whilepatch = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-16 02:51:00 +08:00
|
|
|
compileBlockBody(compiler, BLOCK_LOOP);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
emitLoopJump(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
patchJump(compiler, whilepatch);
|
2021-02-09 16:21:10 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Patch break statement.
|
|
|
|
for (int i = 0; i < compiler->loop->patch_count; i++) {
|
|
|
|
patchJump(compiler, compiler->loop->patches[i]);
|
|
|
|
}
|
|
|
|
compiler->loop = loop.outer_loop;
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
consume(compiler, TK_END, "Expected 'end' after statement end.");
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void compileForStatement(Compiler* compiler) {
|
2021-02-13 01:40:19 +08:00
|
|
|
compilerEnterBlock(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_NAME, "Expected an iterator name.");
|
2021-02-13 01:40:19 +08:00
|
|
|
|
|
|
|
// Unlike functions local variable could shadow a name.
|
2022-04-07 11:28:51 +08:00
|
|
|
const char* iter_name = compiler->parser.previous.start;
|
|
|
|
int iter_len = compiler->parser.previous.length;
|
|
|
|
int iter_line = compiler->parser.previous.line;
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consume(compiler, TK_IN, "Expected 'in' after iterator name.");
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-06-04 09:28:42 +08:00
|
|
|
// Compile and store sequence.
|
|
|
|
compilerAddVariable(compiler, "@Sequence", 9, iter_line); // Sequence
|
2021-02-13 01:40:19 +08:00
|
|
|
compileExpression(compiler);
|
|
|
|
|
2021-05-24 06:17:52 +08:00
|
|
|
// Add iterator to locals. It's an increasing integer indicating that the
|
|
|
|
// current loop is nth starting from 0.
|
2021-06-04 09:28:42 +08:00
|
|
|
compilerAddVariable(compiler, "@iterator", 9, iter_line); // Iterator.
|
2021-05-24 06:17:52 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_0);
|
2021-02-13 01:40:19 +08:00
|
|
|
|
|
|
|
// Add the iteration value. It'll be updated to each element in an array of
|
|
|
|
// each character in a string etc.
|
2021-06-04 09:28:42 +08:00
|
|
|
compilerAddVariable(compiler, iter_name, iter_len, iter_line); // Iter value.
|
2021-02-13 01:40:19 +08:00
|
|
|
emitOpcode(compiler, OP_PUSH_NULL);
|
|
|
|
|
2021-05-24 06:17:52 +08:00
|
|
|
// Start the iteration, and check if the sequence is iterable.
|
|
|
|
emitOpcode(compiler, OP_ITER_TEST);
|
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
Loop loop;
|
2021-02-13 21:57:59 +08:00
|
|
|
loop.start = (int)_FN->opcodes.count;
|
2021-02-13 01:40:19 +08:00
|
|
|
loop.patch_count = 0;
|
|
|
|
loop.outer_loop = compiler->loop;
|
2021-05-13 17:10:57 +08:00
|
|
|
loop.depth = compiler->scope_depth;
|
2021-02-13 01:40:19 +08:00
|
|
|
compiler->loop = &loop;
|
|
|
|
|
|
|
|
// Compile next iteration.
|
|
|
|
emitOpcode(compiler, OP_ITER);
|
|
|
|
int forpatch = emitShort(compiler, 0xffff);
|
|
|
|
|
2021-02-16 02:51:00 +08:00
|
|
|
compileBlockBody(compiler, BLOCK_LOOP);
|
2021-02-13 01:40:19 +08:00
|
|
|
|
2021-05-24 06:17:52 +08:00
|
|
|
emitLoopJump(compiler); //< Loop back to iteration.
|
|
|
|
patchJump(compiler, forpatch); //< Patch exit iteration address.
|
2021-02-13 01:40:19 +08:00
|
|
|
|
|
|
|
// Patch break statement.
|
|
|
|
for (int i = 0; i < compiler->loop->patch_count; i++) {
|
|
|
|
patchJump(compiler, compiler->loop->patches[i]);
|
|
|
|
}
|
|
|
|
compiler->loop = loop.outer_loop;
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
|
|
|
consume(compiler, TK_END, "Expected 'end' after statement end.");
|
2021-02-13 01:40:19 +08:00
|
|
|
compilerExitBlock(compiler); //< Iterator scope.
|
2021-02-09 16:21:10 +08:00
|
|
|
}
|
2021-02-08 02:30:29 +08:00
|
|
|
|
|
|
|
// Compiles a statement. Assignment could be an assignment statement or a new
|
|
|
|
// variable declaration, which will be handled.
|
|
|
|
static void compileStatement(Compiler* compiler) {
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-03-31 01:50:44 +08:00
|
|
|
// is_temporary will be set to true if the statement is an temporary
|
2021-06-08 00:56:56 +08:00
|
|
|
// expression, it'll used to be pop from the stack.
|
2022-03-31 01:50:44 +08:00
|
|
|
bool is_temporary = false;
|
2021-06-07 13:54:06 +08:00
|
|
|
|
2021-06-08 00:56:56 +08:00
|
|
|
// This will be set to true if the statement is an expression. It'll used to
|
|
|
|
// print it's value when running in REPL mode.
|
|
|
|
bool is_expression = false;
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
if (match(compiler, TK_BREAK)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
if (compiler->loop == NULL) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Cannot use 'break' outside a loop.");
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(compiler->loop->patch_count < MAX_BREAK_PATCH,
|
|
|
|
"Too many break statements (" STRINGIFY(MAX_BREAK_PATCH) ")." );
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeEndStatement(compiler);
|
2021-05-13 17:10:57 +08:00
|
|
|
// Pop all the locals at the loop's body depth.
|
|
|
|
compilerPopLocals(compiler, compiler->loop->depth + 1);
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
emitOpcode(compiler, OP_JUMP);
|
2021-06-02 17:33:29 +08:00
|
|
|
int patch = emitShort(compiler, 0xffff); //< Will be patched.
|
2021-02-12 01:35:43 +08:00
|
|
|
compiler->loop->patches[compiler->loop->patch_count++] = patch;
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
} else if (match(compiler, TK_CONTINUE)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
if (compiler->loop == NULL) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Cannot use 'continue' outside a loop.");
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeEndStatement(compiler);
|
2021-05-13 17:10:57 +08:00
|
|
|
// Pop all the locals at the loop's body depth.
|
|
|
|
compilerPopLocals(compiler, compiler->loop->depth + 1);
|
|
|
|
|
2021-02-13 01:40:19 +08:00
|
|
|
emitLoopJump(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
} else if (match(compiler, TK_RETURN)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
if (compiler->scope_depth == DEPTH_GLOBAL) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Invalid 'return' outside a function.");
|
2021-02-12 01:35:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
if (matchEndStatement(compiler)) {
|
2022-04-21 19:53:03 +08:00
|
|
|
|
|
|
|
// Constructors will return self.
|
|
|
|
if (compiler->func->type == FUNC_CONSTRUCTOR) {
|
|
|
|
emitOpcode(compiler, OP_PUSH_SELF);
|
|
|
|
} else {
|
|
|
|
emitOpcode(compiler, OP_PUSH_NULL);
|
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
emitOpcode(compiler, OP_RETURN);
|
2022-04-04 23:07:29 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
} else {
|
2022-04-21 19:53:03 +08:00
|
|
|
|
|
|
|
if (compiler->func->type == FUNC_CONSTRUCTOR) {
|
2022-04-22 20:21:17 +08:00
|
|
|
syntaxError(compiler, compiler->parser.previous,
|
|
|
|
"Cannor 'return' a value from constructor.");
|
2022-04-21 19:53:03 +08:00
|
|
|
}
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler); //< Return value is at stack top.
|
2021-06-13 04:17:44 +08:00
|
|
|
|
2022-04-04 23:07:29 +08:00
|
|
|
// If the last expression parsed with compileExpression() is a call
|
|
|
|
// is_last_call would be true by now.
|
|
|
|
if (compiler->is_last_call) {
|
|
|
|
// Tail call optimization disabled at debug mode.
|
|
|
|
if (compiler->options && !compiler->options->debug) {
|
2021-06-13 04:17:44 +08:00
|
|
|
ASSERT(_FN->opcodes.count >= 2, OOPS); // OP_CALL, argc
|
|
|
|
ASSERT(_FN->opcodes.data[_FN->opcodes.count - 2] == OP_CALL, OOPS);
|
|
|
|
_FN->opcodes.data[_FN->opcodes.count - 2] = OP_TAIL_CALL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeEndStatement(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
emitOpcode(compiler, OP_RETURN);
|
|
|
|
}
|
2021-05-18 19:21:38 +08:00
|
|
|
} else if (match(compiler, TK_IF)) {
|
2021-06-02 17:33:29 +08:00
|
|
|
compileIfStatement(compiler, false);
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
} else if (match(compiler, TK_WHILE)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
compileWhileStatement(compiler);
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
} else if (match(compiler, TK_FOR)) {
|
2021-02-12 01:35:43 +08:00
|
|
|
compileForStatement(compiler);
|
|
|
|
|
|
|
|
} else {
|
2021-02-25 17:03:06 +08:00
|
|
|
compiler->new_local = false;
|
2021-02-12 01:35:43 +08:00
|
|
|
compileExpression(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
consumeEndStatement(compiler);
|
2021-06-08 00:56:56 +08:00
|
|
|
|
|
|
|
is_expression = true;
|
2022-03-31 01:50:44 +08:00
|
|
|
if (!compiler->new_local) is_temporary = true;
|
2021-06-08 00:56:56 +08:00
|
|
|
|
2021-02-25 17:03:06 +08:00
|
|
|
compiler->new_local = false;
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-06-07 13:54:06 +08:00
|
|
|
|
2021-06-18 12:42:57 +08:00
|
|
|
// If running REPL mode, print the expression's evaluated value.
|
2021-06-07 13:54:06 +08:00
|
|
|
if (compiler->options && compiler->options->repl_mode &&
|
2022-04-12 04:49:09 +08:00
|
|
|
compiler->func->ptr == compiler->module->body->fn &&
|
2021-06-08 00:56:56 +08:00
|
|
|
is_expression /*&& compiler->scope_depth == DEPTH_GLOBAL*/) {
|
2021-06-07 13:54:06 +08:00
|
|
|
emitOpcode(compiler, OP_REPL_PRINT);
|
|
|
|
}
|
|
|
|
|
2022-03-31 01:50:44 +08:00
|
|
|
if (is_temporary) emitOpcode(compiler, OP_POP);
|
2021-06-07 13:54:06 +08:00
|
|
|
}
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Compile statements that are only valid at the top level of the module. Such
|
2021-06-07 13:54:06 +08:00
|
|
|
// as import statement, function define, and if we're running REPL mode top
|
2021-06-15 15:37:49 +08:00
|
|
|
// level expression's evaluated value will be printed.
|
2021-06-07 13:54:06 +08:00
|
|
|
static void compileTopLevelStatement(Compiler* compiler) {
|
2021-06-20 18:23:21 +08:00
|
|
|
|
2022-04-06 11:26:51 +08:00
|
|
|
// At the top level the stack size should be 0, before and after compiling
|
|
|
|
// a top level statement, since there aren't any locals at the top level.
|
2022-04-12 18:30:42 +08:00
|
|
|
ASSERT(compiler->parser.has_errors || compiler->func->stack_size == 0, OOPS);
|
2022-04-06 11:26:51 +08:00
|
|
|
|
2021-06-20 23:28:31 +08:00
|
|
|
if (match(compiler, TK_CLASS)) {
|
2022-03-31 02:13:18 +08:00
|
|
|
compileClass(compiler);
|
2021-06-20 23:28:31 +08:00
|
|
|
|
2021-06-07 13:54:06 +08:00
|
|
|
} else if (match(compiler, TK_DEF)) {
|
2022-04-21 19:53:03 +08:00
|
|
|
compileFunction(compiler, FUNC_TOPLEVEL);
|
2021-06-07 13:54:06 +08:00
|
|
|
|
|
|
|
} else if (match(compiler, TK_IMPORT)) {
|
|
|
|
compileRegularImport(compiler);
|
|
|
|
|
2022-05-06 10:46:40 +08:00
|
|
|
} else if (match(compiler, TK_FROM)) {
|
|
|
|
compileFromImport(compiler);
|
2021-06-07 13:54:06 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
compileStatement(compiler);
|
|
|
|
}
|
2022-04-06 11:26:51 +08:00
|
|
|
|
|
|
|
// At the top level the stack size should be 0, before and after compiling
|
|
|
|
// a top level statement, since there aren't any locals at the top level.
|
2022-04-12 18:30:42 +08:00
|
|
|
ASSERT(compiler->parser.has_errors || compiler->func->stack_size == 0, OOPS);
|
2022-04-06 11:26:51 +08:00
|
|
|
|
2021-02-08 02:30:29 +08:00
|
|
|
}
|
|
|
|
|
2022-05-04 14:28:23 +08:00
|
|
|
CompileOptions newCompilerOptions() {
|
|
|
|
CompileOptions options;
|
|
|
|
options.debug = false;
|
|
|
|
options.repl_mode = false;
|
|
|
|
return options;
|
|
|
|
}
|
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
PkResult compile(PKVM* vm, Module* module, const char* source,
|
2022-05-04 14:28:23 +08:00
|
|
|
const CompileOptions* options) {
|
2021-02-12 01:35:43 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
ASSERT(module != NULL, OOPS);
|
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Skip utf8 BOM if there is any.
|
|
|
|
if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
|
|
|
|
|
2021-05-18 19:21:38 +08:00
|
|
|
Compiler _compiler;
|
|
|
|
Compiler* compiler = &_compiler; //< Compiler pointer for quick access.
|
2022-04-11 16:04:22 +08:00
|
|
|
compilerInit(compiler, vm, source, module, options);
|
2021-05-18 19:21:38 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// If compiling for an imported module the vm->compiler would be the compiler
|
|
|
|
// of the module that imported this module. Add the all the compilers into a
|
2021-05-19 02:59:09 +08:00
|
|
|
// link list.
|
|
|
|
compiler->next_compiler = vm->compiler;
|
2021-05-18 19:21:38 +08:00
|
|
|
vm->compiler = compiler;
|
2021-02-13 21:57:59 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// If the module doesn't has a body by default, it's probably was created by
|
2021-07-04 00:24:36 +08:00
|
|
|
// the native api function (pkNewModule() that'll return a module without a
|
|
|
|
// main function) so just create and add the function here.
|
2022-04-11 16:04:22 +08:00
|
|
|
if (module->body == NULL) moduleAddMain(vm, module);
|
2022-04-22 20:21:17 +08:00
|
|
|
ASSERT(module->body != NULL, OOPS);
|
2021-07-04 00:24:36 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// If we're compiling for a module that was already compiled (when running
|
2021-06-15 15:37:49 +08:00
|
|
|
// REPL or evaluating an expression) we don't need the old main anymore.
|
2022-04-11 16:04:22 +08:00
|
|
|
// just use the globals and functions of the module and use a new body func.
|
2022-04-12 04:49:09 +08:00
|
|
|
pkByteBufferClear(&module->body->fn->fn->opcodes, vm);
|
2021-06-08 00:56:56 +08:00
|
|
|
|
2022-04-10 11:07:44 +08:00
|
|
|
// Remember the count of constants, names, and globals, If the compilation
|
|
|
|
// failed discard all of them and roll back.
|
2022-04-11 16:04:22 +08:00
|
|
|
uint32_t constants_count = module->constants.count;
|
|
|
|
uint32_t globals_count = module->globals.count;
|
2021-06-07 13:54:06 +08:00
|
|
|
|
2021-02-13 21:57:59 +08:00
|
|
|
Func curr_fn;
|
2022-04-21 19:53:03 +08:00
|
|
|
compilerPushFunc(compiler, &curr_fn, module->body->fn, FUNC_MAIN);
|
2022-04-12 18:30:42 +08:00
|
|
|
|
2021-02-12 01:35:43 +08:00
|
|
|
// Lex initial tokens. current <-- next.
|
2022-04-22 20:21:17 +08:00
|
|
|
lexToken(compiler);
|
|
|
|
lexToken(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2022-04-22 20:21:17 +08:00
|
|
|
while (!match(compiler, TK_EOF) && !compiler->parser.has_syntax_error) {
|
2021-06-07 13:54:06 +08:00
|
|
|
compileTopLevelStatement(compiler);
|
2021-05-18 19:21:38 +08:00
|
|
|
skipNewLines(compiler);
|
2021-02-12 01:35:43 +08:00
|
|
|
}
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-06-16 02:54:30 +08:00
|
|
|
emitFunctionEnd(compiler);
|
2021-02-07 15:40:00 +08:00
|
|
|
|
2021-05-20 22:05:57 +08:00
|
|
|
// Resolve forward names (function names that are used before defined).
|
2022-04-22 20:21:17 +08:00
|
|
|
if (!compiler->parser.has_syntax_error) {
|
|
|
|
for (int i = 0; i < compiler->parser.forwards_count; i++) {
|
|
|
|
ForwardName* forward = &compiler->parser.forwards[i];
|
|
|
|
const char* name = forward->tkname.start;
|
|
|
|
int length = forward->tkname.length;
|
|
|
|
int index = moduleGetGlobalIndex(compiler->module, name,
|
|
|
|
(uint32_t)length);
|
|
|
|
if (index != -1) {
|
|
|
|
patchForward(compiler, forward->func, forward->instruction, index);
|
|
|
|
} else {
|
|
|
|
// need_more_lines is only true for unexpected EOF errors. For syntax
|
|
|
|
// errors it'll be false by now but. Here it's a semantic errors, so
|
|
|
|
// we're overriding it to false.
|
|
|
|
compiler->parser.need_more_lines = false;
|
|
|
|
resolveError(compiler, forward->tkname, "Name '%.*s' is not defined.",
|
|
|
|
length, name);
|
|
|
|
}
|
2021-05-20 22:05:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 02:59:09 +08:00
|
|
|
vm->compiler = compiler->next_compiler;
|
2021-02-08 02:30:29 +08:00
|
|
|
|
2021-06-08 00:56:56 +08:00
|
|
|
// If compilation failed, discard all the invalid functions and globals.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (compiler->parser.has_errors) {
|
2022-04-11 16:04:22 +08:00
|
|
|
module->constants.count = constants_count;
|
|
|
|
module->globals.count = module->global_names.count = globals_count;
|
2021-06-07 13:54:06 +08:00
|
|
|
}
|
2022-04-08 00:02:20 +08:00
|
|
|
#if DUMP_BYTECODE
|
2022-05-06 10:46:40 +08:00
|
|
|
else {
|
|
|
|
// If there is any syntax errors we cannot dump the bytecode
|
|
|
|
// (otherwise it'll crash with assertion).
|
|
|
|
dumpFunctionCode(compiler->parser.vm, module->body->fn);
|
|
|
|
DEBUG_BREAK();
|
|
|
|
}
|
2021-06-08 00:56:56 +08:00
|
|
|
#endif
|
2021-06-10 07:35:14 +08:00
|
|
|
|
2021-06-09 18:42:26 +08:00
|
|
|
// Return the compilation result.
|
2022-04-07 11:28:51 +08:00
|
|
|
if (compiler->parser.has_errors) {
|
|
|
|
if (compiler->parser.repl_mode && compiler->parser.need_more_lines) {
|
2021-06-09 18:42:26 +08:00
|
|
|
return PK_RESULT_UNEXPECTED_EOF;
|
|
|
|
}
|
|
|
|
return PK_RESULT_COMPILE_ERROR;
|
|
|
|
}
|
|
|
|
return PK_RESULT_SUCCESS;
|
2021-06-07 13:54:06 +08:00
|
|
|
}
|
|
|
|
|
2021-05-19 02:59:09 +08:00
|
|
|
void compilerMarkObjects(PKVM* vm, Compiler* compiler) {
|
2021-06-10 07:35:14 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Mark the module which is currently being compiled.
|
|
|
|
markObject(vm, &compiler->module->_super);
|
2021-04-26 17:34:30 +08:00
|
|
|
|
2022-04-11 16:04:22 +08:00
|
|
|
// Mark the string literals (they haven't added to the module's literal
|
2021-04-26 17:34:30 +08:00
|
|
|
// buffer yet).
|
2022-04-07 11:28:51 +08:00
|
|
|
markValue(vm, compiler->parser.current.value);
|
|
|
|
markValue(vm, compiler->parser.previous.value);
|
|
|
|
markValue(vm, compiler->parser.next.value);
|
2021-05-19 02:59:09 +08:00
|
|
|
|
|
|
|
if (compiler->next_compiler != NULL) {
|
|
|
|
compilerMarkObjects(vm, compiler->next_compiler);
|
|
|
|
}
|
2021-04-26 17:34:30 +08:00
|
|
|
}
|