├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── benchmark ├── fibo.mxc └── loop.mxc ├── example ├── dpfibo.mxc ├── fibo.mxc ├── fizzbuzz.mxc ├── for.mxc ├── hanoi.mxc ├── hello.mxc ├── iter.mxc ├── lifegame.mxc ├── mandelbrot.mxc ├── object.mxc ├── pi.mxc └── sort.mxc ├── include ├── ast.h ├── bytecode.h ├── codegen.h ├── context.h ├── debug.h ├── error │ ├── error.h │ ├── errortype.h │ └── runtime-err.h ├── execarg.h ├── function.h ├── gc.h ├── internal.h ├── keyword.h ├── lexer.h ├── literalpool.h ├── maxc.h ├── mem.h ├── mlib.h ├── mlibapi.h ├── namespace.h ├── object │ ├── attr.h │ ├── encoding.h │ ├── mbool.h │ ├── mdir.h │ ├── mexception.h │ ├── mfiber.h │ ├── mfile.h │ ├── mfloat.h │ ├── mfunc.h │ ├── mint.h │ ├── minteger.h │ ├── miter.h │ ├── mlist.h │ ├── mrange.h │ ├── mstr.h │ ├── mstruct.h │ ├── mtable.h │ ├── mtime.h │ ├── num.h │ ├── object.h │ └── system.h ├── opcode-def.h ├── opcode.h ├── operator.h ├── parser.h ├── scope.h ├── sema.h ├── struct.h ├── token.h ├── type.h ├── util.h ├── vm.h └── vmstate.h ├── lib ├── calendar.mxc ├── math.mxc ├── std.mxc ├── str.mxc └── term.mxc ├── src ├── compiler │ ├── ast.c │ ├── bytecode.c │ ├── codegen.c │ ├── debug.c │ ├── function.c │ ├── lexer.c │ ├── namespace.c │ ├── operator.c │ ├── parser.c │ ├── scope.c │ ├── sema.c │ ├── struct.c │ ├── token.c │ └── type.c ├── error │ └── error.c ├── maxc │ ├── internal.c │ ├── main.c │ └── maxc.c ├── mlib │ ├── api.c │ └── init.c ├── object │ ├── attr.c │ ├── boolean.c │ ├── dir.c │ ├── encoding.c │ ├── exception.c │ ├── fiber.c │ ├── file.c │ ├── float.c │ ├── function.c │ ├── int.c │ ├── integer.c │ ├── iter.c │ ├── list.c │ ├── num.c │ ├── object.c │ ├── range.c │ ├── std.c │ ├── string.c │ ├── struct.c │ ├── table.c │ └── time.c ├── repl │ └── repl.c ├── runtime │ ├── context.c │ ├── execarg.c │ ├── gc.c │ ├── literalpool.c │ ├── mem.c │ └── vm.c └── util │ └── util.c └── test ├── andtest.mxc ├── arg.mxc ├── argv.mxc ├── arith.mxc ├── bignum.mxc ├── bool.mxc ├── comment.mxc ├── file.mxc ├── file └── a.txt ├── float.mxc ├── fntest.mxc ├── for.mxc ├── func.mxc ├── hashtable.mxc ├── if.mxc ├── import.mxc ├── inttof.mxc ├── let.mxc ├── list.mxc ├── logic.mxc ├── noret.mxc ├── not.mxc ├── obid.mxc ├── object.mxc ├── onelinefn.mxc ├── overload.mxc ├── rec.mxc ├── scope.mxc ├── string.mxc ├── struct.mxc ├── switch.mxc ├── test.sh ├── ufcstest.mxc ├── while.mxc └── xortest.mxc /.gitignore: -------------------------------------------------------------------------------- 1 | maxc 2 | !maxc/ 3 | a.out 4 | *.s 5 | *.o 6 | *.swp 7 | core 8 | fast 9 | peda-session-maxc.txt 10 | .gdb_history 11 | .vscode/ 12 | perf* 13 | .clang-format 14 | bug/ 15 | tmp/ 16 | error/ 17 | *.out 18 | *.orig 19 | tags 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | sudo: false 4 | 5 | compiler: gcc 6 | 7 | script: 8 | - make 9 | - make test 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 mrm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | CFLAGS=-Wall -Wextra -lm -std=c11 -I ./include/ -O3 -fno-crossjumping -DNDEBUG 3 | SRCROOT = . 4 | SRCDIRS := $(shell find $(SRCROOT) -type d) 5 | SRCS=$(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) 6 | OBJS=$(SRCS:.c=.o) 7 | TARGET := maxc 8 | .PHONY: test clean 9 | 10 | release: $(OBJS) 11 | $(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(CFLAGS) 12 | 13 | run: $(OBJS) 14 | $(CC) -o $(TARGET) -O3 $(OBJS) $(LDFLAGS) $(CFLAGS) 15 | 16 | debug: $(OBJS) 17 | $(CC) -o $(TARGET) -g -O0 -DNDEBUG $(OBJS) $(LDFLAGS) $(CFLAGS) 18 | 19 | perf: $(OBJS) 20 | $(CC) -o $(TARGET) -g -Og -DNDEBUG $(OBJS) $(LDFLAGS) $(CFLAGS) 21 | 22 | test: $(TARGET) 23 | sh test/test.sh 24 | 25 | clean: 26 | $(RM) $(OBJS) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # maxc 2 | [![](http://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) 3 | [![Build Status](https://travis-ci.com/k-mrm/maxc.svg?branch=master)](https://travis-ci.com/k-mrm/maxc) 4 | 5 | maxc is a scripting language implemented in C. 6 | 7 | - static typing 8 | - comfortable coding 9 | 10 | ## Sample Code 11 | 12 | Please see `/test` directory. 13 | 14 | hello.mxc 15 | ``` 16 | println("Hello, World!"); 17 | ``` 18 | ``` 19 | Hello, World! 20 | ``` 21 | 22 | for.mxc 23 | ``` 24 | for s in ["morning", "evening", "night"] { 25 | println "Good ", s; 26 | } 27 | ``` 28 | ``` 29 | Good morning 30 | Good evening 31 | Good night 32 | ``` 33 | 34 | fibo.mxc 35 | ``` 36 | def fibo(n: int): int { 37 | if n <= 1 { 38 | return n; 39 | } 40 | 41 | return fibo(n - 2) + fibo(n - 1); 42 | } 43 | 44 | 30.fibo().println(); 45 | 30.fibo.println; 46 | ``` 47 | ``` 48 | 832040 49 | 832040 50 | ``` 51 | 52 | ## repl 53 | 54 | ``` 55 | $ ./maxc 56 | Welcome to maxc repl mode! 57 | maxc Version 0.0.1 58 | use exit(int) or Ctrl-D to exit 59 | >> let a = 10 60 | >> a 61 | 10 : int 62 | >> use math@sqrt 63 | >> let n = 2.0 64 | >> n.sqrt 65 | 1.41421356 : float 66 | >> [10; 0] 67 | [0,0,0,0,0,0,0,0,0,0] : [int] 68 | >> 69 | 70 | ``` 71 | 72 | ## How To Build 73 | ### on Linux 74 | 75 | 1. Install gcc and make 76 | 77 | 2. get maxc from github 78 | ``` 79 | $ git clone https://github.com/k-mrm/maxc.git 80 | $ cd maxc 81 | ``` 82 | 83 | 3. Build 84 | ``` 85 | $ make 86 | $ ./maxc # run repl 87 | $ ./maxc example/hello.mxc # run from source file 88 | ``` 89 | 90 | ## Document(Japanese) 91 | https://admarimoin.hatenablog.com/entry/2019/08/28/155346 92 | 93 | -------------------------------------------------------------------------------- /benchmark/fibo.mxc: -------------------------------------------------------------------------------- 1 | def fibo(n: int): int { 2 | if n <= 1 { 3 | return n; 4 | } 5 | else { 6 | return fibo(n-2) + fibo(n-1); 7 | } 8 | } 9 | 10 | 38.fibo.println; 11 | -------------------------------------------------------------------------------- /benchmark/loop.mxc: -------------------------------------------------------------------------------- 1 | let i = 0; 2 | while i != 1000000000 { 3 | i += 1; 4 | } 5 | -------------------------------------------------------------------------------- /example/dpfibo.mxc: -------------------------------------------------------------------------------- 1 | let f = [151; 0]; 2 | 3 | def fibo(n: int): int { 4 | f[0] = 0; 5 | f[1] = 1; 6 | let i = 2; 7 | while i <= n { 8 | f[i] = f[i - 1] + f[i - 2]; 9 | i = i + 1; 10 | } 11 | 12 | return f[n]; 13 | } 14 | 15 | 150.fibo.println; 16 | f.println; 17 | -------------------------------------------------------------------------------- /example/fibo.mxc: -------------------------------------------------------------------------------- 1 | def fibo(n: int): int { 2 | if n <= 1 { 3 | return n; 4 | } 5 | else { 6 | return fibo(n-1) + fibo(n-2); 7 | } 8 | } 9 | 10 | 30.fibo().println(); 11 | 30.fibo.println; 12 | -------------------------------------------------------------------------------- /example/fizzbuzz.mxc: -------------------------------------------------------------------------------- 1 | let i = 1; 2 | 3 | while i <= 600000 { 4 | if i % 15 == 0 { 5 | println("fizzbuzz"); 6 | } 7 | else if i % 5 == 0 { 8 | println("buzz"); 9 | } 10 | else if i % 3 == 0 { 11 | println("fizz"); 12 | } 13 | else { 14 | println(i); 15 | } 16 | 17 | i = i + 1; 18 | } 19 | -------------------------------------------------------------------------------- /example/for.mxc: -------------------------------------------------------------------------------- 1 | for s in ["morning", "evening", "night"] { 2 | println "Good ", s; 3 | } 4 | -------------------------------------------------------------------------------- /example/hanoi.mxc: -------------------------------------------------------------------------------- 1 | def hanoi(n: int, x: string, y: string, z: string) { 2 | if(n > 1) { hanoi(n - 1, x, z, y); } 3 | println(x, "=>", y); 4 | if(n > 1) { hanoi(n - 1, z, y, x); } 5 | } 6 | 7 | hanoi(3, "a", "b", "c"); 8 | -------------------------------------------------------------------------------- /example/hello.mxc: -------------------------------------------------------------------------------- 1 | println("Hello, World!"); 2 | -------------------------------------------------------------------------------- /example/iter.mxc: -------------------------------------------------------------------------------- 1 | iterator fibo(n: int): int { 2 | let f = [n+1; 0]; 3 | f[0] = 0; f[1] = 1; 4 | let i = 2; 5 | while i <= n { 6 | yield f[i] = f[i - 1] + f[i - 2]; 7 | i += 1; 8 | } 9 | } 10 | 11 | for i in fibo(50) { 12 | echo i; 13 | } 14 | -------------------------------------------------------------------------------- /example/lifegame.mxc: -------------------------------------------------------------------------------- 1 | def copy(a: bool[][], b: bool[][], w: int, h: int) { 2 | let { 3 | i = 0; 4 | j = 0; 5 | } 6 | 7 | while i < h { 8 | j = 0; 9 | while j < w { 10 | b[j][i] = a[j][i]; 11 | j = j + 1; 12 | } 13 | i = i + 1; 14 | } 15 | } 16 | 17 | def printb(cur: bool[][], w: int, h: int) { 18 | let { 19 | i = 0; 20 | j = 0; 21 | } 22 | 23 | while i < h { 24 | j = 0; 25 | while j < w { 26 | if cur[j][i] { 27 | "# ".print; 28 | } 29 | else { 30 | "- ".print; 31 | } 32 | 33 | if j == w - 1 { 34 | "".println; 35 | } 36 | j = j + 1; 37 | } 38 | i = i + 1; 39 | } 40 | } 41 | 42 | def search(cur: bool[][], w: int, h: int, x: int, y: int): int { 43 | let { 44 | nalive = 0; 45 | i = 0; 46 | j = 0; 47 | } 48 | 49 | i = y - 1; 50 | while i <= y + 1 { 51 | j = x - 1; 52 | while j <= x + 1 { 53 | if (i != y or j != x) and (j >= 0 and i >= 0 and j < w and i < h) { 54 | if cur[j][i] { 55 | nalive = nalive + 1; 56 | } 57 | } 58 | 59 | j = j + 1; 60 | } 61 | i = i + 1; 62 | } 63 | 64 | return nalive; 65 | } 66 | 67 | def next(w: int, h: int, cur: bool[][], shadow: bool[][]) { 68 | let { 69 | i = 0; 70 | j = 0; 71 | } 72 | 73 | cur.copy(shadow, w, h); 74 | 75 | while i < h { 76 | j = 0; 77 | while j < w { 78 | if cur[j][i] { 79 | if cur.search(w, h, j, i) <= 1 or cur.search(w, h, j, i) >= 4 { 80 | shadow[j][i] = false; 81 | } 82 | } 83 | else { 84 | if cur.search(w, h, j, i) == 3 { 85 | shadow[j][i] = true; 86 | } 87 | } 88 | 89 | j = j + 1; 90 | } 91 | i = i + 1; 92 | } 93 | 94 | shadow.copy(cur, w, h); 95 | } 96 | 97 | def lifegame(w: int, h: int, input: int[], len: int, nnext: int) { 98 | let { 99 | cur_board = [w; [h; false]]; 100 | shadow_board = [w; [h; false]]; 101 | i = 0; 102 | } 103 | 104 | while i < len { 105 | cur_board[input[i] / 10][input[i] % 10] = true; 106 | i = i + 1; 107 | } 108 | 109 | i = 0; 110 | while i < nnext { 111 | next(w, h, cur_board, shadow_board); 112 | i = i + 1; 113 | } 114 | 115 | cur_board.printb(w, h); 116 | } 117 | 118 | let input = [11, 22, 3, 13, 23]; 119 | let i = 1; 120 | 121 | lifegame(20, 20, input, 5, i); 122 | -------------------------------------------------------------------------------- /example/mandelbrot.mxc: -------------------------------------------------------------------------------- 1 | def mandelbrot(cx, cy: float, n: int): float { 2 | let { 3 | xn = 0.0; 4 | yn = 0.0; 5 | xn_1 = 0.0; 6 | yn_1 = 0.0; 7 | i = 0; 8 | } 9 | 10 | while i < n { 11 | xn_1 = xn * xn - (yn * yn) + cx; 12 | yn_1 = 2.0 * xn * yn + cy; 13 | 14 | let t = xn_1 * xn_1 + yn_1 * yn_1; 15 | 16 | if t > 4.0 { 17 | return t; 18 | } 19 | else { 20 | xn = xn_1; 21 | yn = yn_1; 22 | } 23 | 24 | i = i + 1; 25 | } 26 | 27 | return 0.0; 28 | } 29 | 30 | let { 31 | x_max = 2.0; 32 | x_min = -2.0; 33 | y_max = 1.0; 34 | y_min = -1.0; 35 | dx = 0.01; 36 | dy = 0.015; 37 | x = 0.0; 38 | } 39 | 40 | let t = 0.0; 41 | 42 | let y = y_max; 43 | while y > y_min { 44 | x = x_min; 45 | while x < x_max { 46 | t = x.mandelbrot(y, 300); 47 | 48 | if t > 8.0 { "#".print; } 49 | else if t > 6.0 { "*".print; } 50 | else if t > 4.0 { ".".print; } 51 | else { " ".print; } 52 | 53 | x = x + dx; 54 | } 55 | 56 | println(); 57 | y = y - dy; 58 | } 59 | -------------------------------------------------------------------------------- /example/object.mxc: -------------------------------------------------------------------------------- 1 | object Vector { 2 | x: int, 3 | y: int 4 | } 5 | 6 | def put(self: Vector) { 7 | println("vec: ", self.x, " ", self.y); 8 | } 9 | 10 | let a = new Vector; 11 | let b = new Vector; 12 | 13 | a.x = 103; a.y = 110; 14 | b.x = 201; b.y = 319; 15 | 16 | a.put; 17 | b.put; 18 | echo a, b; 19 | -------------------------------------------------------------------------------- /example/pi.mxc: -------------------------------------------------------------------------------- 1 | def pow(base: float, exp: int): float { 2 | let ret: float = 1.0; 3 | 4 | while exp > 0 { 5 | ret *= base; 6 | exp -= 1; 7 | } 8 | 9 | return ret; 10 | } 11 | 12 | def leibniz(n: int): float { 13 | let i: int = 0; 14 | let ret: float = 0.0; 15 | 16 | while i < n { 17 | ret += (-1.0).pow(i) / (2.0 * i.tofloat() + 1.0); 18 | i += 1; 19 | } 20 | 21 | return 4.0 * ret; 22 | } 23 | 24 | println 20000.leibniz(); 25 | -------------------------------------------------------------------------------- /example/sort.mxc: -------------------------------------------------------------------------------- 1 | def bubble_sort(a: int[]) { 2 | let i = 0; 3 | 4 | while i < a.len - 1 { 5 | let j = a.len - 1; 6 | while j > i { 7 | if a[j - 1] > a[j] { 8 | let tmp = a[j - 1]; 9 | a[j - 1] = a[j]; 10 | a[j] = tmp; 11 | } 12 | j -= 1; 13 | } 14 | i += 1; 15 | } 16 | } 17 | 18 | let a = [31, 1, 831, 63, 91, 74, 19]; 19 | a.bubble_sort; 20 | echo a; 21 | -------------------------------------------------------------------------------- /include/ast.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_AST_H 2 | #define MAXC_AST_H 3 | 4 | #include "scope.h" 5 | #include "type.h" 6 | #include "util.h" 7 | #include "operator.h" 8 | #include "object/object.h" 9 | #include "object/attr.h" 10 | 11 | enum NDTYPE { 12 | NDTYPE_NUM = 100, 13 | NDTYPE_BOOL, 14 | NDTYPE_NULL, 15 | NDTYPE_LIST, 16 | NDTYPE_HASHTABLE, 17 | NDTYPE_SUBSCR, 18 | NDTYPE_TUPLE, 19 | NDTYPE_RETURN, 20 | NDTYPE_YIELD, 21 | NDTYPE_BREAK, 22 | NDTYPE_SKIP, 23 | NDTYPE_BREAKPOINT, 24 | NDTYPE_FUNCDEF, 25 | NDTYPE_ITERATOR, 26 | NDTYPE_FUNCCALL, 27 | NDTYPE_FUNCPROTO, 28 | NDTYPE_VARDECL, 29 | NDTYPE_ASSIGNMENT, 30 | NDTYPE_VARIABLE, 31 | NDTYPE_OBJECT, 32 | NDTYPE_STRUCTINIT, 33 | NDTYPE_MODULE, 34 | NDTYPE_BLOCK, 35 | NDTYPE_TYPEDBLOCK, 36 | NDTYPE_STRING, 37 | NDTYPE_BINARY, 38 | NDTYPE_MEMBER, 39 | NDTYPE_DOTEXPR, 40 | NDTYPE_UNARY, 41 | NDTYPE_TERNARY, 42 | NDTYPE_IF, 43 | NDTYPE_EXPRIF, 44 | NDTYPE_FOR, 45 | NDTYPE_WHILE, 46 | NDTYPE_SWITCH, 47 | NDTYPE_MODULEFUNCCALL, 48 | NDTYPE_NAMESPACE, 49 | NDTYPE_ASSERT, 50 | NDTYPE_NONENODE, 51 | }; 52 | 53 | typedef struct Ast { 54 | enum NDTYPE type; 55 | int lineno; 56 | Type *ctype; 57 | } Ast; 58 | 59 | #define AST_HEAD Ast base 60 | #define CTYPE(ast) (((Ast *)(ast))->ctype) 61 | 62 | #define LINENO(ast) (((Ast *)(ast))->lineno) 63 | 64 | struct NodeVariable; 65 | typedef struct NodeFnCall NodeFnCall; 66 | 67 | /* AST definitions */ 68 | 69 | typedef struct NodeNumber { 70 | AST_HEAD; 71 | MxcValue value; 72 | } NodeNumber; 73 | 74 | typedef struct NodeBool { 75 | AST_HEAD; 76 | bool boolean; 77 | } NodeBool; 78 | 79 | typedef struct NodeNull { 80 | AST_HEAD; 81 | } NodeNull; 82 | 83 | typedef struct NodeString { 84 | AST_HEAD; 85 | char *string; 86 | } NodeString; 87 | 88 | typedef struct NodeList { 89 | AST_HEAD; 90 | /* let a = [10, 20, 30, 40]; */ 91 | Vector *elem; 92 | size_t nsize; 93 | /* let a = [200; 0]; */ 94 | Ast *nelem; 95 | Ast *init; 96 | } NodeList; 97 | 98 | typedef struct NodeHashTable { 99 | AST_HEAD; 100 | Vector *key; 101 | Vector *val; 102 | } NodeHashTable; 103 | 104 | typedef struct NodeTuple { 105 | AST_HEAD; 106 | Vector *exprs; 107 | size_t nsize; 108 | } NodeTuple; 109 | 110 | typedef struct NodeBinop { 111 | AST_HEAD; 112 | enum BINOP op; 113 | Ast *left; 114 | Ast *right; 115 | 116 | struct NodeFnCall *impl; 117 | } NodeBinop; 118 | 119 | typedef struct NodeMember { 120 | AST_HEAD; 121 | Ast *left; 122 | Ast *right; 123 | } NodeMember; 124 | 125 | typedef struct NodeSubscript { 126 | AST_HEAD; 127 | Ast *ls; 128 | Ast *index; 129 | bool istuple; // default: list 130 | } NodeSubscript; 131 | 132 | typedef struct NodeUnaop { 133 | AST_HEAD; 134 | enum UNAOP op; 135 | Ast *expr; 136 | } NodeUnaop; 137 | 138 | typedef struct NodeDotExpr { 139 | AST_HEAD; 140 | Ast *left; 141 | Ast *right; 142 | uint8_t flag; 143 | struct { 144 | bool member: 1; 145 | bool fncall: 1; 146 | bool objattr: 1; 147 | } t; 148 | 149 | NodeFnCall *call; 150 | NodeMember *memb; 151 | size_t offset; 152 | enum attr_type attype; 153 | } NodeDotExpr; 154 | 155 | typedef struct NodeAssignment { 156 | AST_HEAD; 157 | Ast *dst; 158 | Ast *src; 159 | } NodeAssignment; 160 | 161 | typedef struct NodeVariable { 162 | AST_HEAD; 163 | char *name; 164 | bool isglobal; 165 | size_t vid; 166 | int vattr; 167 | bool used; // for warning 168 | /* built-in function */ 169 | /* for overload */ 170 | bool is_overload; 171 | } NodeVariable; 172 | 173 | typedef struct NodeVardecl { 174 | AST_HEAD; 175 | NodeVariable *var; 176 | Ast *init; 177 | 178 | /* decl block */ 179 | bool is_block; 180 | Vector *block; 181 | } NodeVardecl; 182 | 183 | typedef struct NodeObject { 184 | AST_HEAD; 185 | char *tagname; 186 | Vector *decls; 187 | } NodeObject; 188 | 189 | typedef struct NodeStructInit { 190 | AST_HEAD; 191 | Type *tag; 192 | Vector *fields; 193 | Vector *inits; 194 | } NodeStructInit; 195 | 196 | /* Node func */ 197 | struct NodeBlock; 198 | 199 | typedef struct NodeFunction { 200 | AST_HEAD; 201 | NodeVariable *fnvar; 202 | Ast *block; 203 | Vector *args; 204 | Vector *lvars; 205 | bool is_generic; 206 | bool is_iterator; 207 | 208 | int op; // operator overloading 209 | /* generic */ 210 | Vector *typevars; 211 | } NodeFunction; 212 | 213 | struct NodeFnCall { 214 | AST_HEAD; 215 | Ast *func; 216 | Vector *args; 217 | }; 218 | 219 | typedef struct NodeReturn { 220 | AST_HEAD; 221 | Ast *cont; 222 | } NodeReturn; 223 | 224 | typedef struct NodeYield { 225 | AST_HEAD; 226 | Ast *cont; 227 | } NodeYield; 228 | 229 | typedef struct NodeBreak { 230 | AST_HEAD; 231 | int label; 232 | } NodeBreak; 233 | 234 | typedef struct NodeSkip { 235 | AST_HEAD; 236 | } NodeSkip; 237 | 238 | typedef struct NodeBreakPoint { 239 | AST_HEAD; 240 | } NodeBreakPoint; 241 | 242 | typedef struct NodeIf { 243 | AST_HEAD; 244 | Ast *cond; 245 | Ast *then_s, *else_s; 246 | bool isexpr; 247 | } NodeIf; 248 | 249 | typedef struct NodeFor { 250 | AST_HEAD; 251 | Vector *vars; 252 | Ast *iter; 253 | Ast *body; 254 | } NodeFor; 255 | 256 | typedef struct NodeWhile { 257 | AST_HEAD; 258 | Ast *cond; 259 | Ast *body; 260 | } NodeWhile; 261 | 262 | typedef struct NodeSwitch { 263 | AST_HEAD; 264 | Ast *match; 265 | Vector *ecase; 266 | Vector *body; 267 | Ast *eelse; 268 | } NodeSwitch; 269 | 270 | typedef struct NodeBlock { 271 | AST_HEAD; 272 | Vector *cont; 273 | } NodeBlock; 274 | 275 | /* NodeNameSpace extends NodeVariable */ 276 | /* 277 | * use std@{upto, a} 278 | */ 279 | 280 | typedef struct NodeNameSpace { 281 | NodeVariable base; 282 | char *name; 283 | NodeBlock *block; 284 | Vector *usenames; 285 | } NodeNameSpace; 286 | 287 | typedef struct NodeModuleFuncCall { 288 | AST_HEAD; 289 | Ast *name; 290 | Ast *ident; 291 | } NodeModuleFuncCall; 292 | 293 | typedef struct NodeAssert { 294 | AST_HEAD; 295 | Ast *cond; 296 | } NodeAssert; 297 | 298 | typedef struct NoneNode_ { 299 | AST_HEAD; 300 | } NoneNode_; 301 | 302 | bool ast_isexpr(Ast *); 303 | bool node_is_number(Ast *); 304 | 305 | extern NoneNode_ nonenode; 306 | #define NONE_NODE ((Ast *)&nonenode) 307 | 308 | NodeNumber *node_number_int(int64_t, int); 309 | NodeNumber *node_number_float(double, int); 310 | NodeNumber *node_number_big(MxcValue, int); 311 | NodeBool *node_bool(bool, int); 312 | NodeNull *node_null(int); 313 | NodeString *node_string(char *, int); 314 | NodeList *node_list(Vector *, size_t, Ast *, Ast *, int); 315 | NodeHashTable *node_hashtable(Vector *, Vector *, int); 316 | NodeBinop *node_binary(enum BINOP, Ast *, Ast *, int); 317 | NodeReturn *node_return(Ast *, int); 318 | NodeYield *node_yield(Ast *, int); 319 | NodeIf *node_if(Ast *, Ast *, Ast *, bool, int); 320 | NodeFor *node_for(Vector *, Ast *, Ast *, int); 321 | NodeWhile *node_while(Ast *, Ast *, int); 322 | NodeMember *node_member(Ast *, Ast *, int); 323 | NodeDotExpr *node_dotexpr(Ast *, Ast *, int); 324 | NodeSubscript *node_subscript(Ast *, Ast *, int); 325 | NodeUnaop *node_unary(enum UNAOP, Ast *, int); 326 | NodeFunction *node_function(NodeVariable *, Ast *, Vector *, Vector *, bool, int); 327 | NodeFnCall *node_fncall(Ast *, Vector *, int); 328 | NodeAssignment *node_assign(Ast *, Ast *, int); 329 | NodeVardecl *node_vardecl(NodeVariable *, Ast *, Vector *, int); 330 | NodeVariable *node_variable(char *, int, int); 331 | NodeVariable *node_variable_type(char *, int, Type *, int); 332 | NodeSwitch *node_switch(Ast *match, Vector *ecase, Vector *body, Ast *eelse, int lineno); 333 | NodeObject *node_object(char *, Vector *, int); 334 | NodeStructInit *node_struct_init(Type *, Vector *, Vector *, int); 335 | NodeBlock *node_block(Vector *, int); 336 | NodeBreak *node_break(int); 337 | NodeSkip *node_skip(int); 338 | NodeBreakPoint *node_breakpoint(int); 339 | NodeBlock *node_typedblock(Vector *, int); 340 | NodeNameSpace *node_namespace(char *, NodeBlock *, int, Vector *); 341 | NodeModuleFuncCall *node_modulefunccall(Ast *, Ast *, int); 342 | NodeAssert *node_assert(Ast *, int); 343 | 344 | #define CAST_AST(node) ((Ast *)(node)) 345 | #define CAST_TYPE(ty) ((Type *)(ty)) 346 | 347 | #endif 348 | -------------------------------------------------------------------------------- /include/bytecode.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_BYTECODE_H 2 | #define MAXC_BYTECODE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "maxc.h" 8 | #include "util.h" 9 | #include "opcode.h" 10 | 11 | typedef struct Bytecode { 12 | mptr_t *code; 13 | uint16_t len; 14 | uint16_t reserved; 15 | } Bytecode; 16 | 17 | Bytecode *new_bytecode(void); 18 | 19 | void op_addr_table_init(); 20 | void pushop(Bytecode *self, enum OPCODE); 21 | void pusharg(Bytecode *self, mptr_t); 22 | void replace_int(size_t, Bytecode *, int64_t); 23 | 24 | #ifdef MXC_DEBUG 25 | void codedump(mptr_t[], size_t *, Vector *); 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/codegen.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_BYTECODE_GEN_H 2 | #define MAXC_BYTECODE_GEN_H 3 | 4 | #include "maxc.h" 5 | #include "debug.h" 6 | #include "bytecode.h" 7 | 8 | struct cgen { 9 | struct cgen *prev; 10 | Bytecode *iseq; 11 | MxcValue *gvars; 12 | int ngvars; 13 | Vector *ltable; 14 | Vector *loopstack; 15 | DebugInfo *d; 16 | }; 17 | 18 | struct cgen *compile(Vector *, int); 19 | struct cgen *compile_repl(Vector *, struct cgen *); 20 | 21 | struct cgen *newcgen_glb(int ngvars); 22 | struct cgen *newcgen(struct cgen *p, char *name); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/context.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_FRAME_H 2 | #define MXC_FRAME_H 3 | 4 | #include 5 | #include "maxc.h" 6 | #include "debug.h" 7 | #include "bytecode.h" 8 | #include "function.h" 9 | #include "object/object.h" 10 | #include "object/mexception.h" 11 | 12 | struct MFiber; 13 | typedef struct MContext MContext; 14 | struct MContext { 15 | MContext *prev; 16 | char *filename; 17 | mptr_t *code; 18 | size_t codesize; 19 | Vector *lvar_info; 20 | MxcValue *lvars; 21 | size_t nlvars; 22 | mptr_t *pc; 23 | mptr_t *basepc; 24 | MException *exc; 25 | int err_handling_enabled; 26 | 27 | struct MFiber *fiber; 28 | 29 | DebugInfo *d; 30 | }; 31 | 32 | MContext *new_econtext(mptr_t *, size_t, DebugInfo *, MContext *); 33 | void delete_context(MContext *); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_DEBUG_H 2 | #define MXC_DEBUG_H 3 | 4 | #include "maxc.h" 5 | #include "util.h" 6 | 7 | typedef struct DebugInfo DebugInfo; 8 | struct DebugInfo { 9 | Vector *var_info; 10 | const char *filename; 11 | char *name; 12 | Vector *pc_line_map; 13 | }; 14 | 15 | DebugInfo *new_debuginfo(const char *filename, char *name); 16 | int curlineno(DebugInfo *d, mptr_t *pc, mptr_t *base); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/error/error.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_ERROR_ERROR_H 2 | #define MXC_ERROR_ERROR_H 3 | 4 | #include "maxc.h" 5 | #include "token.h" 6 | 7 | #ifdef MXC_DEBUG 8 | #define mxc_assert(expr, msg) mxc_assert_core(expr, msg, __FILE__, __LINE__) 9 | #else 10 | #define mxc_assert(expr, msg) 11 | #endif 12 | 13 | #define unreachable() unreachable_core(__FILE__, __LINE__) 14 | 15 | void error(const char *, ...); 16 | void errline(int, char *, ...); 17 | void warn(const char *, ...); 18 | void error_at(const SrcPos, const SrcPos, const char *, ...); 19 | void mxc_unimplemented(const char *, ...); 20 | void expect_token(const SrcPos, const SrcPos, const char *); 21 | void warning(const SrcPos, const SrcPos, const char *, ...); 22 | void debug(const char *, ...); 23 | void showline(int, int); 24 | 25 | void putsline(int lineno); 26 | 27 | void mxc_assert_core(int, char *, char *, int); 28 | void unreachable_core(char *, int) __attribute__((noreturn)); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/error/errortype.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_ERRORTYPE_H 2 | #define MXC_ERRORTYPE_H 3 | 4 | enum RuntimeErrType { 5 | RTERR_NONEERR, 6 | RTERR_OUTOFRANGE, 7 | RTERR_ZERO_DIVISION, 8 | RTERR_ASSERT, 9 | RTERR_UNIMPLEMENTED, 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/error/runtime-err.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_RUNTIME_ERR_H 2 | #define MXC_RUNTIME_ERR_H 3 | 4 | #include "error/errortype.h" 5 | #include "object/object.h" 6 | 7 | struct MContext; 8 | struct MxcObject; 9 | typedef struct MxcObject MxcObject; 10 | typedef struct MContext MContext; 11 | 12 | typedef struct RuntimeErr { 13 | enum RuntimeErrType type; 14 | MxcValue args[2]; 15 | int argc; 16 | } RuntimeErr; 17 | 18 | void mxc_raise_err(MContext *frame, enum RuntimeErrType); 19 | void raise_outofrange(MContext *, MxcValue, MxcValue); 20 | void runtime_error(MContext *); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/execarg.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_EXECARG_H 2 | #define MXC_EXECARG_H 3 | 4 | #include "object/object.h" 5 | 6 | struct execarg { 7 | MxcValue top; 8 | MxcValue second; /* if ncache == 1, treat as stack top */ 9 | 10 | MxcValue *argv; 11 | } __attribute__((__packed__)); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/function.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_BLTINFN_H 2 | #define MAXC_BLTINFN_H 3 | 4 | #include "debug.h" 5 | #include "bytecode.h" 6 | #include "util.h" 7 | 8 | typedef struct userfunction { 9 | uint16_t codesize; 10 | uint16_t nlvars; 11 | uint64_t *code; 12 | DebugInfo *d; 13 | } userfunction; 14 | 15 | userfunction *new_userfunction(Bytecode *c, DebugInfo *d, size_t nlvars); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/gc.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_GC_H 2 | #define MXC_GC_H 3 | 4 | #include "mem.h" 5 | #include "context.h" 6 | 7 | extern MContext *cur_frame; 8 | 9 | typedef struct GCHeap { 10 | struct GCHeap *next; 11 | MxcObject *obj; 12 | } GCHeap; 13 | 14 | extern GCHeap root; 15 | extern GCHeap *tailp; 16 | 17 | void heap_dump(void); 18 | size_t heap_length(void); 19 | void gc_run(void); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/internal.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_INTERNAL_H 2 | #define MXC_INTERNAL_H 3 | 4 | #include 5 | #include 6 | 7 | #ifndef NDEBUG 8 | #define MXC_DEBUG 9 | #endif /* !NDEBUG */ 10 | 11 | #define STR_DEFAULT "\e[0m" 12 | #define BOLD(s) "\e[1m" s "\e[0m" 13 | #define MUTED(s) "\e[2m" s "\e[0m" 14 | 15 | #define MXC_VERSION "0.0.1" 16 | #define INTERN_UNUSE(v) ((void)v) 17 | 18 | #define log_error(...) fprintf(stderr, __VA_ARGS__) 19 | 20 | #ifdef MXC_DEBUG 21 | # define log_dbg(...) fprintf(stderr, __VA_ARGS__) 22 | #else 23 | # define log_dbg(...) 24 | #endif 25 | 26 | typedef struct ReadStatus ReadStatus; 27 | 28 | struct ReadStatus { 29 | char *str; 30 | struct { 31 | unsigned int eof: 1; 32 | unsigned int toolong: 1; 33 | } err; 34 | }; 35 | 36 | extern const unsigned int intern_ascii_to_numtable[]; 37 | 38 | ReadStatus intern_readline(size_t, size_t *, char *, size_t); 39 | int64_t intern_scan_digiti(char *, int, int *, size_t *); 40 | int32_t intern_scan_digiti32(char *, int, int *, size_t *); 41 | uint64_t intern_scan_digitu(char *, int, int *, size_t *); 42 | 43 | void *xmalloc(size_t); 44 | void panic(char *, ...); 45 | 46 | #endif /* MXC_INTERNAL_H */ 47 | -------------------------------------------------------------------------------- /include/keyword.h: -------------------------------------------------------------------------------- 1 | KEYWORD("int", TKIND_TInt) 2 | KEYWORD("bool", TKIND_TBool) 3 | KEYWORD("string", TKIND_TString) 4 | KEYWORD("float", TKIND_TFloat) 5 | KEYWORD("none", TKIND_TNone) 6 | KEYWORD("or", TKIND_KOr) 7 | KEYWORD("and", TKIND_KAnd) 8 | KEYWORD("object", TKIND_Object) 9 | KEYWORD("return", TKIND_Return) 10 | KEYWORD("if", TKIND_If) 11 | KEYWORD("else", TKIND_Else) 12 | KEYWORD("for", TKIND_For) 13 | KEYWORD("while", TKIND_While) 14 | KEYWORD("typedef", TKIND_Typedef) 15 | KEYWORD("let", TKIND_Let) 16 | KEYWORD("def", TKIND_Def) 17 | KEYWORD("true", TKIND_True) 18 | KEYWORD_ALIAS("yes", TKIND_True) 19 | KEYWORD("false", TKIND_False) 20 | KEYWORD_ALIAS("no", TKIND_False) 21 | KEYWORD("const", TKIND_Const) 22 | KEYWORD("yield", TKIND_YIELD) 23 | KEYWORD("use", TKIND_Use) 24 | KEYWORD("Error", TKIND_TError) 25 | KEYWORD("failure", TKIND_FAILURE) 26 | KEYWORD("break", TKIND_Break) 27 | KEYWORD("skip", TKIND_Skip) 28 | KEYWORD("new", TKIND_New) 29 | KEYWORD("in", TKIND_In) 30 | KEYWORD("null", TKIND_Null) 31 | KEYWORD("xor", TKIND_Xor) 32 | KEYWORD("assert", TKIND_Assert) 33 | KEYWORD("File", TKIND_TFile) 34 | KEYWORD("iterator", TKIND_ITERATOR) 35 | KEYWORD("switch", TKIND_SWITCH) 36 | KEYWORD("case", TKIND_CASE) 37 | -------------------------------------------------------------------------------- /include/lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_LEXER_H 2 | #define MAXC_LEXER_H 3 | 4 | #include "util.h" 5 | 6 | Vector *lexer_run(const char *, const char *); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/literalpool.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_CONST_H 2 | #define MAXC_CONST_H 3 | 4 | #include "function.h" 5 | #include "util.h" 6 | #include "object/object.h" 7 | 8 | enum LITKIND { 9 | LIT_STR, 10 | LIT_FNUM, 11 | LIT_LONG, 12 | LIT_FUNC, 13 | LIT_RAWOBJ, 14 | }; 15 | 16 | typedef struct Literal { 17 | enum LITKIND kind; 18 | union { 19 | char *str; // str 20 | double fnumber; 21 | int64_t lnum; 22 | userfunction *func; 23 | MxcValue raw; 24 | }; 25 | } Literal; 26 | 27 | Literal *New_Literal(); 28 | Literal *New_Literal_With_Str(char *); 29 | Literal *New_Literal_Long(int64_t); 30 | Literal *New_Literal_With_Fnumber(double); 31 | Literal *New_Literal_With_Userfn(userfunction *); 32 | Literal *New_Literal_Object(MxcValue); 33 | int lpool_push_str(Vector *, char *); 34 | int lpool_push_long(Vector *, int64_t); 35 | int lpool_push_float(Vector *, double); 36 | int lpool_push_userfunc(Vector *, userfunction *); 37 | int lpool_push_object(Vector *, MxcValue); 38 | 39 | void lpooldump(Vector *); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/maxc.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_H 2 | #define MAXC_H 3 | 4 | #include 5 | #include "internal.h" 6 | #include "util.h" 7 | 8 | #ifdef __code_model_32__ 9 | typedef int32_t smptr_t; 10 | typedef uint32_t mptr_t; 11 | #else 12 | typedef int64_t smptr_t; 13 | typedef uint64_t mptr_t; 14 | #endif 15 | 16 | #if __GNUC__ >= 3 17 | #define LIKELY(x) (__builtin_expect(!!(x), 1)) 18 | #define UNLIKELY(x) (__builtin_expect(!!(x), 0)) 19 | #else 20 | #define LIKELY(x) (x) 21 | #define UNLIKELY(x) (x) 22 | #endif 23 | 24 | int mxc_main_file(const char *); 25 | int mxc_main_repl(void); 26 | 27 | void mxc_open(int, char **); 28 | void mxc_close(); 29 | 30 | // #define DIRECT_THREADED 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_MEM_H 2 | #define MAXC_MEM_H 3 | 4 | #include "object/object.h" 5 | #include "object/minteger.h" 6 | #include "object/mbool.h" 7 | #include "object/mfloat.h" 8 | #include "object/mfunc.h" 9 | #include "object/mint.h" 10 | #include "object/mlist.h" 11 | #include "object/mstr.h" 12 | #include "object/mstruct.h" 13 | #include "object/mtable.h" 14 | #include "object/mfile.h" 15 | #include "object/mdir.h" 16 | 17 | #define OBJECT_POOL 18 | 19 | #ifdef OBJECT_POOL 20 | union obalign { 21 | MInteger i; 22 | MList l; 23 | MDir d; 24 | MFile f; 25 | MStat st; 26 | MStrct strc; 27 | MString s; 28 | MxcFunction fn; 29 | MxcCFunc cf; 30 | MException e; 31 | MTable t; 32 | }; 33 | 34 | typedef struct ObjectPool { 35 | MxcObject **pool; 36 | uint16_t len; 37 | uint16_t reserved; 38 | } ObjectPool; 39 | 40 | #define OBPOOL_LAST (obpool.pool[obpool.len - 1]) 41 | 42 | void New_Objectpool(void); 43 | void obpool_push(MxcObject *); 44 | 45 | #endif 46 | 47 | #ifdef OBJECT_POOL 48 | # define Mxc_free(ob) do { \ 49 | obpool_push((MxcObject *)(ob)); \ 50 | } while(0) 51 | #else 52 | # define Mxc_free(ob) free(ob) 53 | #endif /* OBJECT_POOL */ 54 | 55 | #ifndef USE_MARK_AND_SWEEP 56 | # define INCREF(ob) (++((MxcObject *)(ob))->refcount) 57 | 58 | # define DECREF(ob) \ 59 | do { \ 60 | if(--((MxcObject *)(ob))->refcount == 0) { \ 61 | SYSTEM((MxcObject *)ob)->dealloc((MxcObject *)ob); \ 62 | } \ 63 | } while(0) 64 | #else 65 | # define INCREF(ob) ((void)0) 66 | # define DECREF(ob) ((void)0) 67 | #endif /* USE_MARK_AND_SWEEP */ 68 | 69 | #define GC_MARK(ob) (SYSTEM(ob)->mark((MxcObject *)(ob))) 70 | #define GC_GUARD(ob) (SYSTEM(ob)->guard((MxcObject *)(ob))) 71 | #define GC_UNGUARD(ob) (SYSTEM(ob)->unguard((MxcObject *)(ob))) 72 | 73 | MxcObject *mxc_alloc(size_t); 74 | 75 | #endif /* MAXC_MEM_H */ 76 | -------------------------------------------------------------------------------- /include/mlib.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_MLIB_H 2 | #define MXC_MLIB_H 3 | 4 | #include "maxc.h" 5 | #include "mlibapi.h" 6 | 7 | void std_init(void); 8 | void file_init(void); 9 | void str_init(void); 10 | void list_init(void); 11 | void dir_init(void); 12 | void int_init(void); 13 | void time_init(void); 14 | 15 | void module_init(void); 16 | 17 | void setup_argv(int argc, char **argv); 18 | 19 | extern Vector *gmodule; 20 | 21 | #define FTYPE(...) __VA_ARGS__, NULL 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/mlibapi.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_MLIBAPI_H 2 | #define MXC_MLIBAPI_H 3 | 4 | #include "ast.h" 5 | #include "type.h" 6 | #include "context.h" 7 | #include "object/object.h" 8 | #include "object/mfunc.h" 9 | 10 | typedef struct MxcCBltin MxcCBltin; 11 | 12 | typedef struct MxcModule { 13 | char *name; 14 | Vector *cimpl; 15 | Vector *cmeth; 16 | Vector *ctypes; 17 | } MxcModule; 18 | 19 | typedef struct _MxcCMethod { 20 | NodeVariable *var; 21 | cfunction meth; 22 | } _MxcCMethod; 23 | 24 | typedef struct MCimpl { 25 | NodeVariable *var; 26 | MxcValue impl; 27 | } MCimpl; 28 | 29 | MxcModule *new_mxcmodule(char *); 30 | void define_cfunc(MxcModule *, char *, cfunction, Type *, ...); 31 | void define_cmeth(MxcModule *, char *, cfunction, Type *, ...); 32 | void define_cconst(MxcModule *, char *, MxcValue, Type *); 33 | 34 | void define_ctype(MxcModule *, Type *); 35 | 36 | int mlib_parse_arg(MxcValue *arg, int narg, ...); 37 | 38 | void reg_gmodule(MxcModule *m); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/namespace.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_NAMESPACE_H 2 | #define MAXC_NAMESPACE_H 3 | 4 | #include "util.h" 5 | 6 | typedef struct Namespace { 7 | char *name; 8 | Vector *vars; 9 | } Namespace; 10 | 11 | extern Vector *namespace_table; 12 | 13 | void reg_namespace(char *, Vector *); 14 | Vector *search_namespace(char *); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/object/attr.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OBJECT_ATTR_H 2 | #define MXC_OBJECT_ATTR_H 3 | 4 | #include 5 | #include 6 | #include "object/object.h" 7 | #include "type.h" 8 | 9 | enum attr_state { 10 | ATTR_READABLE = 0x1, 11 | ATTR_WRITABLE = 0x2, 12 | }; 13 | 14 | enum attr_type { 15 | ATTY_CINT, 16 | ATTY_CFLOAT, 17 | ATTY_CBOOL, 18 | ATTY_MVALUE, 19 | }; 20 | 21 | struct mobj_attr { 22 | char *attrname; 23 | size_t offset; 24 | enum attr_state state; 25 | enum attr_type attype; 26 | Type *type; 27 | size_t ty_memb_off; 28 | }; 29 | 30 | MxcValue mxc_objattrget(MxcObject *, char *name); 31 | void mxc_objattrset(MxcObject *, char *name, MxcValue src); 32 | 33 | struct mobj_attr mxc_objattr(struct mobj_attr *attrs, char *name); 34 | 35 | extern struct mobj_attr list_attr[]; 36 | extern struct mobj_attr table_attr[]; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/object/encoding.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OBJECT_ENCODING_H 2 | #define MXC_OBJECT_ENCODING_H 3 | 4 | enum encoding { 5 | ENC_UTF8, 6 | }; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /include/object/mbool.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_BOOLOBJECT_H 2 | #define MXC_BOOLOBJECT_H 3 | 4 | #include 5 | #include "object/object.h" 6 | 7 | static inline MxcValue bool_logor(MxcValue l, MxcValue r) { 8 | if(V2I(l) || V2I(r)) 9 | return mval_true; 10 | else 11 | return mval_false; 12 | } 13 | 14 | static inline MxcValue bool_logand(MxcValue l, MxcValue r) { 15 | if(V2I(l) && V2I(r)) 16 | return mval_true; 17 | else 18 | return mval_false; 19 | } 20 | 21 | static inline MxcValue bool_not(MxcValue u) { 22 | if(V2I(u)) 23 | return mval_false; 24 | else 25 | return mval_true; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/object/mdir.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OBJECT_MDIR_H 2 | #define MXC_OBJECT_MDIR_H 3 | 4 | #include 5 | #include 6 | #include "object/object.h" 7 | 8 | typedef struct MDir MDir; 9 | struct MDir { 10 | OBJECT_HEAD; 11 | MString *path; 12 | DIR *dir; 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/object/mexception.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_EXCEPTION_H 2 | #define MXC_EXCEPTION_H 3 | 4 | #include "object/object.h" 5 | #include "object/mstr.h" 6 | 7 | typedef struct MException MException; 8 | struct MException { 9 | OBJECT_HEAD; 10 | char *errname; 11 | MString *msg; 12 | }; 13 | 14 | #define EXC_OUTOFRANGE (&exc_outofrange) 15 | #define EXC_ZERO_DIVISION (&exc_zero_division) 16 | #define EXC_ASSERT (&exc_assert) 17 | #define EXC_FILE (&exc_file) 18 | #define EXC_EOF (&exc_eof) 19 | #define EXC_NOTFOUND (&exc_notfound) 20 | 21 | #define NEW_EXCEPTION(exc, name) \ 22 | MException exc = { \ 23 | { NULL, GCGUARD_FLAG }, \ 24 | name, \ 25 | NULL, \ 26 | } 27 | 28 | extern MException exc_outofrange; 29 | extern MException exc_zero_division; 30 | extern MException exc_assert; 31 | extern MException exc_file; 32 | extern MException exc_eof; 33 | extern MException exc_notfound; 34 | 35 | void mxc_raise(MException *, char *, ...); 36 | void exc_report(MException *); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/object/mfiber.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_MFIBER_H 2 | #define MXC_MFIBER_H 3 | 4 | #include "object/object.h" 5 | #include "context.h" 6 | 7 | enum fiberstate { 8 | CREATED, 9 | SUSPENDING, 10 | RUNNING, 11 | DEAD, 12 | }; 13 | 14 | typedef struct MFiber MFiber; 15 | struct MFiber { 16 | OBJECT_HEAD; 17 | enum fiberstate state; 18 | MContext *ctx; 19 | }; 20 | 21 | MxcValue new_mfiber(userfunction *, MContext *); 22 | MxcValue fiber_resume(MxcObject *); 23 | MxcValue fiber_yield(MContext *, MxcValue *, size_t); 24 | MxcValue myield(MContext *c, MxcValue arg); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/object/mfile.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_FILEOBJECT_H 2 | #define MXC_FILEOBJECT_H 3 | 4 | #include 5 | #include 6 | #include "object/object.h" 7 | #include "object/mstr.h" 8 | 9 | typedef struct MStat MStat; 10 | struct MStat { 11 | OBJECT_HEAD; 12 | struct stat st; 13 | }; 14 | 15 | typedef struct MFile MFile; 16 | struct MFile { 17 | OBJECT_HEAD; 18 | MString *path; 19 | FILE *file; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/object/mfloat.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_FLOATOBJECT_H 2 | #define MXC_FLOATOBJECT_H 3 | 4 | #include "object/object.h" 5 | 6 | struct MxcBool; 7 | typedef struct MxcBool MxcBool; 8 | 9 | typedef struct MxcFloat { 10 | OBJECT_HEAD; 11 | double fnum; 12 | } MxcFloat; 13 | 14 | MxcValue float_eq(MxcValue, MxcValue); 15 | MxcValue float_neq(MxcValue, MxcValue); 16 | MxcValue float_lt(MxcValue, MxcValue); 17 | MxcValue float_gt(MxcValue, MxcValue); 18 | MxcValue float_div(MxcValue, MxcValue); 19 | 20 | #define FloatAdd(l, r) (mval_float(V2F(l) + V2F(r))) 21 | #define FloatSub(l, r) (mval_float(V2F(l) - V2F(r))) 22 | #define FloatMul(l, r) (mval_float(V2F(l) * V2F(r))) 23 | #define FloatDiv(l, r) (mval_float(V2F(l) / V2F(r))) 24 | 25 | MxcValue float_tostring(MxcValue); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/object/mfunc.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_FUNCTIONOBJECT_H 2 | #define MXC_FUNCTIONOBJECT_H 3 | 4 | #include "function.h" 5 | #include "object/object.h" 6 | #include "context.h" 7 | 8 | typedef struct MCallable MCallable; 9 | 10 | typedef int (*callfn_t)(MCallable *, MContext *, size_t); 11 | typedef MxcValue (*cfunction)(MxcValue *, size_t); 12 | 13 | struct MCallable { 14 | OBJECT_HEAD; 15 | callfn_t call; 16 | }; 17 | 18 | #define CALLABLE_HEAD MCallable head; 19 | 20 | typedef struct MxcFunction { 21 | CALLABLE_HEAD; 22 | userfunction *func; 23 | bool iter: 1; 24 | } MxcFunction; 25 | 26 | typedef struct MxcCFunc { 27 | CALLABLE_HEAD; 28 | cfunction func; 29 | } MxcCFunc; 30 | 31 | MxcValue new_function(userfunction *, bool); 32 | MxcValue new_cfunc(cfunction); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/object/mint.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_INTOBJECT_H 2 | #define MXC_INTOBJECT_H 3 | 4 | #include 5 | #include "object/object.h" 6 | #include "object/minteger.h" 7 | 8 | struct MxcBool; 9 | typedef struct MxcBool MxcBool; 10 | 11 | void int_divrem(MxcValue, MxcValue, MxcValue *, MxcValue *); 12 | MxcValue int_tostring(MxcValue); 13 | 14 | #define mul_overflow_chk(x, y) \ 15 | ((x) == 0 ? 0 : \ 16 | (x) == -1 ? (y) < -(INT32_MAX) : \ 17 | (x) > 0 ? \ 18 | ((y) > 0 ? INT32_MAX / (x) < (y) : INT32_MIN / (x) > (y)) : \ 19 | ((y) > 0 ? INT32_MIN / (x) < (y) : INT32_MAX / (x) > (y))) 20 | 21 | static inline MxcValue int_copy(MxcValue v) { 22 | return v; 23 | } 24 | 25 | static inline MxcValue int_add(MxcValue l, MxcValue r) { 26 | int32_t res; 27 | if(__builtin_add_overflow(V2I(l), V2I(r), &res)) { 28 | l = int_to_integer(V2I(l)); 29 | r = int_to_integer(V2I(r)); 30 | return integer_add(l, r); 31 | } 32 | return mval_int(res); 33 | } 34 | 35 | static inline MxcValue int_sub(MxcValue l, MxcValue r) { 36 | int32_t res; 37 | if(__builtin_sub_overflow(V2I(l), V2I(r), &res)) { 38 | l = int_to_integer(V2I(l)); 39 | r = int_to_integer(V2I(r)); 40 | return integer_sub(l, r); 41 | } 42 | return mval_int(res); 43 | } 44 | 45 | static inline MxcValue int_mul(MxcValue l, MxcValue r) { 46 | if(mul_overflow_chk(V2I(l), V2I(r))) { 47 | l = int_to_integer(V2I(l)); 48 | r = int_to_integer(V2I(r)); 49 | return integer_mul(l, r); 50 | } 51 | return mval_int(V2I(l) * V2I(r)); 52 | } 53 | 54 | static inline MxcValue int_div(MxcValue l, MxcValue r) { 55 | MxcValue quo; 56 | int_divrem(l, r, &quo, NULL); 57 | return quo; 58 | } 59 | 60 | static inline MxcValue int_rem(MxcValue l, MxcValue r) { 61 | MxcValue rem; 62 | int_divrem(l, r, NULL, &rem); 63 | return rem; 64 | } 65 | 66 | static inline MxcValue int_xor(MxcValue l, MxcValue r) { 67 | return mval_int(V2I(l) ^ V2I(r)); 68 | } 69 | 70 | static inline MxcValue int_eq(MxcValue l, MxcValue r) { 71 | if(V2I(l) == V2I(r)) 72 | return mval_true; 73 | else 74 | return mval_false; 75 | } 76 | 77 | static inline MxcValue int_noteq(MxcValue l, MxcValue r) { 78 | if(V2I(l) != V2I(r)) 79 | return mval_true; 80 | else 81 | return mval_false; 82 | } 83 | 84 | static inline MxcValue int_lt(MxcValue l, MxcValue r) { 85 | if(V2I(l) < V2I(r)) 86 | return mval_true; 87 | else 88 | return mval_false; 89 | } 90 | 91 | static inline MxcValue int_lte(MxcValue l, MxcValue r) { 92 | if(V2I(l) <= V2I(r)) 93 | return mval_true; 94 | else 95 | return mval_false; 96 | } 97 | 98 | static inline MxcValue int_gt(MxcValue l, MxcValue r) { 99 | if(V2I(l) > V2I(r)) 100 | return mval_true; 101 | else 102 | return mval_false; 103 | } 104 | 105 | static inline MxcValue int_gte(MxcValue l, MxcValue r) { 106 | if(V2I(l) >= V2I(r)) 107 | return mval_true; 108 | else 109 | return mval_false; 110 | } 111 | 112 | MxcValue int2str(MxcValue val, int base); 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /include/object/minteger.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_INTEGEROBJECT_H 2 | #define MXC_INTEGEROBJECT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "object/object.h" 8 | 9 | #define SIZEOF_DIGIT_T (sizeof(int)) 10 | #define DIGIT_POW (SIZEOF_DIGIT_T * CHAR_BIT) 11 | #define DIGIT_BASE ((digit2_t)1 << DIGIT_POW) 12 | #define DIGIT_MAX (DIGIT_BASE - 1) 13 | 14 | typedef unsigned int digit_t; 15 | typedef unsigned long long digit2_t; 16 | typedef signed int sdigit_t; 17 | typedef signed long long sdigit2_t; 18 | 19 | enum { 20 | SIGN_MINUS = 0, 21 | SIGN_PLUS = 1, 22 | }; 23 | 24 | typedef struct MInteger { 25 | OBJECT_HEAD; 26 | size_t len; 27 | digit_t *digit; 28 | char sign; 29 | } MInteger; 30 | 31 | MxcValue new_integer(char *, int); 32 | MxcValue int_to_integer(int64_t); 33 | MxcValue uint_to_integer(uint64_t); 34 | MxcValue integer_copy(MxcObject *); 35 | MxcValue integer_add(MxcValue, MxcValue); 36 | MxcValue integer_sub(MxcValue, MxcValue); 37 | MxcValue integer_mul(MxcValue, MxcValue); 38 | MxcValue integer_eq(MxcValue, MxcValue); 39 | MxcValue integer_divrem(MxcValue, MxcValue, MxcValue *); 40 | MxcValue integer_tostring(MxcObject *); 41 | 42 | MxcValue integer2str(MInteger *self, int base); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/object/miter.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_ITEROBJECT_H 2 | #define MXC_ITEROBJECT_H 3 | 4 | #include 5 | #include "object/object.h" 6 | 7 | struct MxcIterable { 8 | OBJECT_HEAD; 9 | size_t length; 10 | size_t index; 11 | }; 12 | 13 | MxcValue iterable_reset(MxcIterable *); 14 | MxcValue iterable_next(MxcIterable *); 15 | MxcValue iterable_stopped(MxcIterable *); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/object/mlist.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_LISTOBJECT_H 2 | #define MXC_LISTOBJECT_H 3 | 4 | #include "object/object.h" 5 | #include "object/miter.h" 6 | 7 | #define LISTLEN(l) (ITERABLE((l))->length) 8 | #define LISTCAPA(l) ((l)->capa) 9 | 10 | typedef struct MList { 11 | ITERABLE_OBJECT_HEAD; 12 | int capa; 13 | MxcValue *elem; 14 | } MList; 15 | 16 | MxcValue new_list(size_t); 17 | MxcValue new_list2(MxcValue *es, size_t nes); 18 | MxcValue new_list_size(MxcValue, MxcValue); 19 | MxcValue mlistset(MList *l, MxcValue idx, MxcValue a); 20 | MxcValue mlistget(MList *l, MxcValue idx); 21 | MxcValue listadd(MList *, MxcValue); 22 | 23 | MxcValue list_tostring(MxcObject *); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/object/mrange.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_MRANGE_H 2 | #define MXC_MRANGE_H 3 | 4 | #include "object/object.h" 5 | 6 | typedef struct MRange MRange; 7 | struct MRange { 8 | OBJECT_HEAD; 9 | MxcValue begin; 10 | MxcValue end; 11 | int excl; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/object/mstr.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_STRINGOBJECT_H 2 | #define MXC_STRINGOBJECT_H 3 | 4 | #include 5 | #include "object/object.h" 6 | #include "object/miter.h" 7 | 8 | #define STRLEN(s) (ITERABLE(s)->length) 9 | 10 | struct MString { 11 | ITERABLE_OBJECT_HEAD; 12 | char *str; 13 | bool isdyn; 14 | }; 15 | 16 | MxcValue new_string(char *, size_t); 17 | MxcValue new_string_copy(char *, size_t); 18 | MxcValue new_string_static(char *, size_t); 19 | MxcValue str_concat(MString *, MString *); 20 | void str_append(MString *, MString *); 21 | void str_cstr_append(MString *, char *, size_t); 22 | MxcValue mstr_eq(MxcValue *, size_t); 23 | 24 | MxcValue string_tostring(MxcObject *); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/object/mstruct.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_MSTRUCT_H 2 | #define MXC_MSTRUCT_H 3 | 4 | #include "object/object.h" 5 | 6 | typedef struct MxcIStruct { 7 | OBJECT_HEAD; 8 | MxcValue *field; 9 | uint16_t nfield; 10 | } MStrct; 11 | 12 | MxcValue new_struct(int); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/object/mtable.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_TABLE_H 2 | #define MXC_TABLE_H 3 | 4 | #include 5 | #include "object/object.h" 6 | #include "object/mstr.h" 7 | 8 | struct mentry { 9 | struct mentry *next; 10 | MxcValue key; 11 | MxcValue val; 12 | }; 13 | 14 | typedef struct MTable MTable; 15 | struct MTable { 16 | ITERABLE_OBJECT_HEAD; 17 | int nentry; 18 | int nslot; 19 | struct mentry **e; 20 | MxcValue default_val; 21 | }; 22 | 23 | MxcValue new_table_capa(int); 24 | void mtable_add(MTable *, MxcValue, MxcValue); 25 | void table_set_default(MTable *t, MxcValue def); 26 | MxcValue tablegetitem(MxcIterable *self, MxcValue index); 27 | MxcValue tablesetitem(MxcIterable *self, MxcValue index, MxcValue a); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/object/mtime.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OBJECT_TIME_H 2 | #define MXC_OBJECT_TIME_H 3 | 4 | #include 5 | #include 6 | #include "object/object.h" 7 | 8 | typedef struct MTime MTime; 9 | struct MTime { 10 | OBJECT_HEAD; 11 | struct tm time; 12 | }; 13 | 14 | MxcValue time_from_utime(time_t utime); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/object/num.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OBJECT_NUM_H 2 | #define MXC_OBJECT_NUM_H 3 | 4 | #include "object/object.h" 5 | #include "object/minteger.h" 6 | #include "object/mint.h" 7 | 8 | MxcValue num_add(MxcValue, MxcValue); 9 | MxcValue num_sub(MxcValue, MxcValue); 10 | MxcValue num_mul(MxcValue, MxcValue); 11 | MxcValue num_div(MxcValue, MxcValue); 12 | MxcValue num_mod(MxcValue, MxcValue); 13 | MxcValue num_neg(MxcValue); 14 | MxcValue num_eq(MxcValue, MxcValue); 15 | MxcValue num_noteq(MxcValue, MxcValue); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/object/object.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_OBJECT_H 2 | #define MAXC_OBJECT_H 3 | 4 | #include 5 | #include 6 | 7 | #define OBJECT_HEAD MxcObject base 8 | #define ITERABLE_OBJECT_HEAD MxcIterable base 9 | #define ITERABLE(ob) ((MxcIterable *)(ob)) 10 | 11 | #define USE_MARK_AND_SWEEP 12 | 13 | #define NAN_BOXING 14 | 15 | typedef struct MxcValue MxcValue; 16 | 17 | struct MContext; 18 | typedef struct MContext MContext; 19 | struct MString; 20 | typedef struct MString MString; 21 | 22 | typedef struct MxcObject MxcObject; 23 | typedef struct MxcIterable MxcIterable; 24 | 25 | #define NEW_OBJECT(obtype, name, sys) \ 26 | obtype *name; \ 27 | do { \ 28 | name = (obtype *)mxc_alloc(sizeof(obtype)); \ 29 | SYSTEM(name) = &(sys); \ 30 | } while(0) 31 | 32 | #define SYSTEM(ob) (((MxcObject *)(ob))->sys) 33 | 34 | #define GCMARK_FLAG 0b01 35 | #define GCGUARD_FLAG 0b10 36 | 37 | #define OBJGCMARK(ob) ((MxcObject *)(ob))->flag |= GCMARK_FLAG 38 | #define OBJGCUNMARK(ob) ((MxcObject *)(ob))->flag &= ~GCMARK_FLAG 39 | #define OBJGCMARKED(ob) (((MxcObject *)(ob))->flag & GCMARK_FLAG) 40 | #define OBJGCGUARD(ob) ((MxcObject *)(ob))->flag |= GCGUARD_FLAG 41 | #define OBJGCUNGUARD(ob) ((MxcObject *)(ob))->flag &= ~GCGUARD_FLAG 42 | #define OBJGCGUARDED(ob) (((MxcObject *)(ob))->flag & GCGUARD_FLAG) 43 | 44 | struct mobj_system; 45 | struct MxcObject { 46 | struct mobj_system *sys; 47 | /* 48 | * 8bit flag 49 | * rrrrrrgm 50 | * 51 | * r: reserved 52 | * g: gc guard 53 | * m: gc marked 54 | */ 55 | uint8_t flag; 56 | }; 57 | 58 | #ifdef NAN_BOXING 59 | struct MxcValue { 60 | union { 61 | double d; 62 | uint64_t raw; 63 | }; 64 | }; 65 | 66 | enum valuet { 67 | VAL_INVALID = 0b000, 68 | VAL_NULL = 0b100, 69 | VAL_FALSE = 0b010, 70 | VAL_TRUE = 0b101, 71 | VAL_INT = 0b001, 72 | VAL_OBJ = 0b011, 73 | VAL_FLO = 0b111, 74 | }; 75 | #else /* NAN_BOXING */ 76 | enum valuet { 77 | VAL_INT = 0b00000001, 78 | VAL_FLO = 0b00000010, 79 | VAL_TRUE = 0b00000100, 80 | VAL_FALSE = 0b00001000, 81 | VAL_NULL = 0b00010000, 82 | VAL_OBJ = 0b00100000, 83 | VAL_INVALID = 0b00000000, 84 | }; 85 | 86 | struct MxcValue { 87 | enum valuet t: 8; 88 | union { 89 | MxcObject *obj; 90 | int64_t num; 91 | double fnum; 92 | }; 93 | }; 94 | #endif /* NAN_BOXING */ 95 | 96 | /* 97 | * float: FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 98 | * obj: 1111111111110011 PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP PPPPPPPPPPPPPPPP 99 | * int: 1111111111110001 0000000000000000 IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII 100 | */ 101 | 102 | #ifdef NAN_BOXING 103 | 104 | #define MNAN 0xfff0000000000000lu 105 | 106 | #define mval_int(i) (MxcValue){ .raw = (MNAN | ((uint64_t)VAL_INT << 48) | (uint32_t)(i)) } 107 | #define mval_float(f) (MxcValue){ .d = (f) } 108 | #define mval_obj(p) (MxcValue){ .raw = (MNAN | ((uint64_t)VAL_OBJ << 48) | (uint64_t)(p)) } 109 | #define mval_true (MxcValue){ .raw = (MNAN | ((uint64_t)VAL_TRUE << 48) | 1) } 110 | #define mval_false (MxcValue){ .raw = (MNAN | ((uint64_t)VAL_FALSE << 48)) } 111 | #define mval_bool(b) ((b)? mval_true : mval_false) 112 | #define mval_null (MxcValue){ .raw = (MNAN | ((uint64_t)VAL_NULL << 48)) } 113 | #define mval_invalid (MxcValue){ .raw = MNAN } 114 | #define mval_raw(r) (MxcValue){ .raw = r } 115 | 116 | #define mval_type(v) ((((v).raw) & MNAN) == MNAN? (((v).raw) >> 48) & 0xf : VAL_FLO) 117 | 118 | #define V2I(v) ((int32_t)(((v).raw) & 0xffffffff)) 119 | #define V2O(v) ((MxcObject *)(((v).raw) & 0xffffffffffff)) 120 | #define V2F(v) ((v).d) 121 | #define obig(v) ((MInteger *)V2O(v)) 122 | #define ostr(v) ((MString *)V2O(v)) 123 | #define ocallee(v) ((MCallable *)V2O(v)) 124 | #define olist(v) ((MList *)V2O(v)) 125 | #define ofile(v) ((MFile *)V2O(v)) 126 | #define ostrct(v) ((MStrct *)V2O(v)) 127 | 128 | #define isobj(v) (mval_type(v) == VAL_OBJ) 129 | #define isint(v) (mval_type(v) == VAL_INT) 130 | #define isbool(v) (mval_type(v) == VAL_TRUE || mval_type(v) == VAL_FALSE) 131 | #define istrue(v) (mval_type(v) == VAL_TRUE) 132 | #define isfalse(v) (mval_type(v) == VAL_FALSE) 133 | #define isflo(v) (mval_type(v) == VAL_FLO) 134 | 135 | #define check_value(v) ((v).raw != MNAN) 136 | 137 | #define val_raw(v) ((v).raw) 138 | 139 | #else /* !NAN_BOXING */ 140 | 141 | #define mval_type(v) ((v).t) 142 | 143 | #define mval_int(v) (MxcValue){ .t = VAL_INT, .num = (v) } 144 | #define mval_float(v) (MxcValue){ .t = VAL_FLO, .fnum = (v) } 145 | #define mval_true (MxcValue){ .t = VAL_TRUE, .num = 1 } 146 | #define mval_false (MxcValue){ .t = VAL_FALSE, .num = 0 } 147 | #define mval_null (MxcValue){ .t = VAL_NULL, .num = 0 } 148 | #define mval_obj(v) (MxcValue){ .t = VAL_OBJ, .obj = (MxcObject *)(v) } 149 | #define mval_invalid (MxcValue){ .t = VAL_INVALID, {0}} 150 | 151 | #define check_value(v) ((v).t) 152 | #define isobj(v) ((v).t & VAL_OBJ) 153 | #define isint(v) ((v).t & VAL_INT) 154 | #define isbool(v) ((v).t & (VAL_TRUE | VAL_FALSE)) 155 | #define istrue(v) ((v).t == VAL_TRUE) 156 | #define isfalse(v) ((v).t == VAL_FALSE) 157 | #define isflo(v) ((v).t & VAL_FLO) 158 | 159 | #define V2I(v) ((v).num) 160 | #define V2F(v) ((v).fnum) 161 | #define V2O(v) ((v).obj) 162 | #define obig(v) ((MInteger *)(v).obj) 163 | #define ostr(v) ((MString *)(v).obj) 164 | #define ocallee(v) ((MCallable *)(v).obj) 165 | #define olist(v) ((MList *)(v).obj) 166 | #define ofile(v) ((MFile *)(v).obj) 167 | #define ostrct(v) ((MStrct *)(v).obj) 168 | 169 | #endif /* NAN_BOXING */ 170 | 171 | #define mval_debug(v) (ostr(mval2str(v))->str) 172 | 173 | MxcValue mval2str(MxcValue); 174 | MxcValue mval_copy(MxcValue); 175 | bool mval_eq(MxcValue, MxcValue); 176 | void mgc_mark(MxcValue); 177 | void mgc_guard(MxcValue); 178 | void mgc_unguard(MxcValue); 179 | 180 | uint32_t obj_hash32(MxcObject *ob); 181 | uint32_t mval_hash32(MxcValue v); 182 | 183 | extern const char mxc_36digits[]; 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /include/object/system.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_SYSTEM_H 2 | #define MXC_SYSTEM_H 3 | 4 | #include 5 | #include 6 | #include "object/object.h" 7 | #include "object/attr.h" 8 | 9 | struct mobj_system { 10 | char *type_name; 11 | struct mobj_attr *attr; 12 | 13 | MxcValue (*tostring)(MxcObject *); 14 | void (*dealloc)(MxcObject *); 15 | MxcValue (*copy)(MxcObject *); 16 | void (*mark)(MxcObject *); 17 | void (*guard)(MxcObject *); 18 | void (*unguard)(MxcObject *); 19 | MxcValue (*get)(MxcIterable *, MxcValue); 20 | MxcValue (*set)(MxcIterable *, MxcValue, MxcValue); 21 | MxcValue (*getiter)(MxcObject *); 22 | MxcValue (*iter_next)(MxcObject *); 23 | MxcValue (*iter_stopped)(MxcObject *); 24 | uint32_t (*hash)(MxcObject *); 25 | bool (*eq)(MxcObject *, MxcObject *); 26 | }; 27 | 28 | extern struct mobj_system integer_sys; 29 | extern struct mobj_system float_sys; 30 | extern struct mobj_system string_sys; 31 | extern struct mobj_system char_sys; 32 | extern struct mobj_system bool_true_sys; 33 | extern struct mobj_system bool_false_sys; 34 | extern struct mobj_system null_sys; 35 | extern struct mobj_system list_sys; 36 | extern struct mobj_system userfn_sys; 37 | extern struct mobj_system cfn_sys; 38 | extern struct mobj_system fiber_sys; 39 | extern struct mobj_system table_sys; 40 | extern struct mobj_system dir_sys; 41 | extern struct mobj_system stat_sys; 42 | extern struct mobj_system time_sys; 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/opcode-def.h: -------------------------------------------------------------------------------- 1 | OPCODE_DEF(END) 2 | OPCODE_DEF(PUSH) 3 | OPCODE_DEF(IPUSH) 4 | OPCODE_DEF(PUSHCONST_0) 5 | OPCODE_DEF(PUSHCONST_1) 6 | OPCODE_DEF(PUSHCONST_2) 7 | OPCODE_DEF(PUSHCONST_3) 8 | OPCODE_DEF(PUSHTRUE) 9 | OPCODE_DEF(PUSHFALSE) 10 | OPCODE_DEF(PUSHNULL) 11 | OPCODE_DEF(FPUSH) 12 | OPCODE_DEF(POP) 13 | OPCODE_DEF(ADD) 14 | OPCODE_DEF(SUB) 15 | OPCODE_DEF(MUL) 16 | OPCODE_DEF(DIV) 17 | OPCODE_DEF(MOD) 18 | OPCODE_DEF(LOGOR) 19 | OPCODE_DEF(LOGAND) 20 | OPCODE_DEF(BXOR) 21 | OPCODE_DEF(EQ) 22 | OPCODE_DEF(NOTEQ) 23 | OPCODE_DEF(LT) 24 | OPCODE_DEF(LTE) 25 | OPCODE_DEF(GT) 26 | OPCODE_DEF(GTE) 27 | OPCODE_DEF(FADD) 28 | OPCODE_DEF(FSUB) 29 | OPCODE_DEF(FMUL) 30 | OPCODE_DEF(FDIV) 31 | OPCODE_DEF(FMOD) 32 | OPCODE_DEF(FLOGOR) 33 | OPCODE_DEF(FLOGAND) 34 | OPCODE_DEF(FEQ) 35 | OPCODE_DEF(FNOTEQ) 36 | OPCODE_DEF(FLT) 37 | OPCODE_DEF(FLTE) 38 | OPCODE_DEF(FGT) 39 | OPCODE_DEF(FGTE) 40 | OPCODE_DEF(JMP) 41 | OPCODE_DEF(JMP_EQ) 42 | OPCODE_DEF(JMP_NOTEQ) 43 | OPCODE_DEF(NOT) 44 | OPCODE_DEF(INEG) 45 | OPCODE_DEF(FNEG) 46 | OPCODE_DEF(LOAD_GLOBAL) 47 | OPCODE_DEF(LOAD_LOCAL) 48 | OPCODE_DEF(STORE_GLOBAL) 49 | OPCODE_DEF(STORE_LOCAL) 50 | OPCODE_DEF(LISTSET) 51 | OPCODE_DEF(LISTSET_SIZE) 52 | OPCODE_DEF(SUBSCR) 53 | OPCODE_DEF(SUBSCR_STORE) 54 | OPCODE_DEF(STRINGSET) 55 | OPCODE_DEF(FUNCTIONSET) 56 | OPCODE_DEF(ITERFN_SET) 57 | OPCODE_DEF(STRUCTSET) 58 | OPCODE_DEF(TABLESET) 59 | OPCODE_DEF(RET) 60 | OPCODE_DEF(YIELD) 61 | OPCODE_DEF(CALL) 62 | OPCODE_DEF(ITERCALL) 63 | OPCODE_DEF(MEMBER_LOAD) 64 | OPCODE_DEF(MEMBER_STORE) 65 | OPCODE_DEF(ITER) 66 | OPCODE_DEF(ITER_NEXT) 67 | OPCODE_DEF(STRCAT) 68 | OPCODE_DEF(BREAKPOINT) 69 | OPCODE_DEF(ASSERT) 70 | OPCODE_DEF(TRY) 71 | OPCODE_DEF(CATCH) 72 | OPCODE_DEF(SWITCH_DISPATCH) 73 | OPCODE_DEF(OBJATTR_READ) 74 | OPCODE_DEF(OBJATTR_WRITE) 75 | -------------------------------------------------------------------------------- /include/opcode.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_OPCODE_H 2 | #define MXC_OPCODE_H 3 | 4 | #include "maxc.h" 5 | 6 | enum OPCODE { 7 | #ifdef DIRECT_THREADED 8 | # define OPCODE_DEF(op) OP_ ## op, 9 | # include "opcode-def.h" 10 | # undef OPCODE_DEF 11 | #else 12 | # define OPCODE_DEF(op) \ 13 | OP_ ## op, /* base(dummy) */ \ 14 | OP_ ## op ## _SCXX, /* SCXX base * 6 + 1 */\ 15 | OP_ ## op ## _SCAX, \ 16 | OP_ ## op ## _SCBX, \ 17 | OP_ ## op ## _SCBA, \ 18 | OP_ ## op ## _SCAB, 19 | # include "opcode-def.h" 20 | # undef OPCODE_DEF 21 | #endif 22 | }; 23 | 24 | #endif /* MXC_OPCODE_H */ 25 | -------------------------------------------------------------------------------- /include/operator.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_OPERATOR_H 2 | #define MAXC_OPERATOR_H 3 | 4 | #include "util.h" 5 | #include "object/mfunc.h" 6 | 7 | struct NodeFunction; 8 | struct Type; 9 | typedef struct NodeFunction NodeFunction; 10 | typedef struct Type Type; 11 | 12 | enum MXC_OPERATOR { 13 | OPE_BINARY, 14 | OPE_UNARY, 15 | OPE_INVALID = -1, 16 | }; 17 | 18 | enum BINOP { 19 | BIN_ADD, 20 | BIN_SUB, 21 | BIN_MUL, 22 | BIN_DIV, 23 | BIN_MOD, 24 | BIN_EQ, 25 | BIN_NEQ, 26 | BIN_LT, 27 | BIN_LTE, 28 | BIN_GT, 29 | BIN_GTE, 30 | BIN_LAND, 31 | BIN_LOR, 32 | BIN_LSHIFT, 33 | BIN_RSHIFT, 34 | BIN_BXOR, 35 | BIN_DOTDOT, 36 | BIN_QUESTION, 37 | BINOP_INVALID = -1, 38 | }; 39 | 40 | enum UNAOP { 41 | UNA_INC, 42 | UNA_DEC, 43 | UNA_PLUS, 44 | UNA_MINUS, 45 | UNA_NOT, /* ! */ 46 | UNAOP_INVALID = -1, 47 | }; 48 | 49 | Type *operator_type(enum MXC_OPERATOR, int, Type *, Type *); 50 | char *operator_dump(enum MXC_OPERATOR, int); 51 | enum BINOP op_char1(char c); 52 | enum BINOP op_char2(char c1, char c2); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_PARSER_H 2 | #define MAXC_PARSER_H 3 | 4 | #include "util.h" 5 | 6 | /* parser state */ 7 | struct mparser { 8 | struct mparser *prev; 9 | Vector *tokens; 10 | Vector *ast; 11 | int pos; 12 | int err; 13 | }; 14 | 15 | struct mparser *parser_run(Vector *); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/scope.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_ENV_H 2 | #define MAXC_ENV_H 3 | 4 | #include 5 | 6 | #include "type.h" 7 | #include "util.h" 8 | 9 | enum VARATTR { 10 | VARATTR_CONST = 0b0001, 11 | VARATTR_UNINIT = 0b0010, 12 | }; 13 | 14 | enum scopetype { 15 | BLOCKSCOPE, 16 | FUNCSCOPE, 17 | }; 18 | 19 | typedef struct Scope Scope; 20 | struct Scope { 21 | Scope *parent; 22 | Vector *vars; 23 | Vector *userdef_type; 24 | Vector *fscope_vars; 25 | enum scopetype type; 26 | bool fscope_gbl; 27 | int err; 28 | int ngvar; 29 | }; 30 | 31 | Scope *make_scope(Scope *, enum scopetype); 32 | Scope *scope_escape(Scope *); 33 | void scope_push_var(Scope *, NodeVariable *); 34 | size_t var_assign_id(Scope *); 35 | int chk_var_conflict(Scope *, NodeVariable *); 36 | NodeVariable *searchbyname(Scope *s, char *name); 37 | 38 | #define scope_isglobal(scope) (!scope->parent) 39 | #define fscope_isglobal(scope) (scope->fscope_gbl) 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/sema.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_SEMA_H 2 | #define MAXC_SEMA_H 3 | 4 | #include 5 | #include "maxc.h" 6 | #include "type.h" 7 | #include "util.h" 8 | #include "scope.h" 9 | 10 | typedef struct SemaResult SemaResult; 11 | 12 | struct SemaResult { 13 | Scope *scope; 14 | bool isexpr; 15 | char *tyname; 16 | }; 17 | 18 | Scope *sema_analysis(Vector *); 19 | SemaResult sema_analysis_repl(Vector *ast); 20 | void sema_init(void); 21 | Type *solvetype(Type *); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/struct.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_STRUCT_H 2 | #define MXC_STRUCT_H 3 | 4 | #include 5 | 6 | struct NodeVariable; 7 | typedef struct NodeVariable NodeVariable; 8 | 9 | typedef struct MxcStruct { 10 | char *name; 11 | NodeVariable **field; 12 | size_t nfield; 13 | } MxcStruct; 14 | 15 | MxcStruct new_cstruct(char *name, NodeVariable **f, size_t nf); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/token.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_TOKEN_H 2 | #define MAXC_TOKEN_H 3 | 4 | #include "util.h" 5 | 6 | enum tkind { 7 | TKIND_End, 8 | TKIND_Num, 9 | TKIND_String, 10 | TKIND_Char, 11 | TKIND_Identifer, 12 | TKIND_BQLIT, 13 | /* Keyword */ 14 | #define KEYWORD(_, k) k, 15 | #define KEYWORD_ALIAS(a, b) 16 | #include "keyword.h" 17 | TKIND_TUint, 18 | TKIND_TInt64, 19 | TKIND_TUint64, 20 | TKIND_TChar, 21 | #undef KEYWORD 22 | #undef KEYWORD_ALIAS 23 | /* Symbol */ 24 | TKIND_Lparen, /* ( */ 25 | TKIND_Rparen, /* ) */ 26 | TKIND_Lbrace, /* { */ 27 | TKIND_Rbrace, /* } */ 28 | TKIND_Lboxbracket, /* [ */ 29 | TKIND_Rboxbracket, /* ] */ 30 | TKIND_Comma, /* , */ 31 | TKIND_Colon, /* : */ 32 | TKIND_Dot, /* . */ 33 | TKIND_DotDot, /* .. */ 34 | TKIND_Semicolon, /* ; */ 35 | TKIND_Arrow, /* -> */ 36 | TKIND_FatArrow, /* => */ 37 | TKIND_Inc, /* ++ */ 38 | TKIND_Dec, /* -- */ 39 | TKIND_Plus, /* + */ 40 | TKIND_Minus, /* - */ 41 | TKIND_Asterisk, /* * */ 42 | TKIND_Div, /* / */ 43 | TKIND_Mod, /* % */ 44 | TKIND_PlusAs, /* += */ 45 | TKIND_MinusAs, /* -= */ 46 | TKIND_AsteriskAs, /* *= */ 47 | TKIND_DivAs, /* /= */ 48 | TKIND_ModAs, /* %= */ 49 | TKIND_Eq, /* == */ 50 | TKIND_Neq, /* != */ 51 | TKIND_Lt, /* < */ 52 | TKIND_Lte, /* <= */ 53 | TKIND_Gt, /* > */ 54 | TKIND_Gte, /* >= */ 55 | TKIND_LogAnd, /* && */ 56 | TKIND_LogOr, /* || */ 57 | TKIND_Lshift, /* << */ 58 | TKIND_Rshift, /* >> */ 59 | TKIND_Assign, /* = */ 60 | TKIND_Bang, /* ! */ 61 | TKIND_Question, /* ? */ 62 | TKIND_Atmark, /* @ */ 63 | TKIND_Hash, /* # */ 64 | }; 65 | 66 | typedef struct SrcPos { 67 | const char *filename; 68 | int line; 69 | int col; 70 | } SrcPos; 71 | 72 | #define cur_srcpos(f, l, c) ((SrcPos){f, l, c}) 73 | 74 | typedef struct Token { 75 | enum tkind kind; 76 | int cont; 77 | char *value; 78 | uint32_t len; 79 | /* source position */ 80 | SrcPos start; 81 | SrcPos end; 82 | } Token; 83 | 84 | char *tkind2str(enum tkind); 85 | char *tk2str(Token *); 86 | void token_push_num(Vector *, char *, uint8_t, SrcPos, SrcPos); 87 | void token_push_symbol(Vector *, enum tkind, uint8_t, SrcPos, SrcPos); 88 | void token_push_ident(Vector *, char *, uint8_t, SrcPos, SrcPos); 89 | void token_push_string(Vector *, char *, uint32_t, SrcPos, SrcPos); 90 | void token_push_char(Vector *, char, SrcPos, SrcPos); 91 | void token_push_backquote_lit(Vector *, char *, uint8_t, SrcPos, SrcPos); 92 | void token_push_end(Vector *, SrcPos, SrcPos); 93 | enum tkind tk_char1(int); 94 | enum tkind tk_char2(int, int); 95 | 96 | #ifdef MXC_DEBUG 97 | void tokendump(Vector *); 98 | #endif 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /include/type.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_TYPE_H 2 | #define MAXC_TYPE_H 3 | 4 | #include 5 | 6 | #include "struct.h" 7 | #include "util.h" 8 | #include "operator.h" 9 | 10 | #define MXCTYPE_HEADER Type parent; 11 | 12 | enum ttype { 13 | CTYPE_NONE, 14 | CTYPE_INT, 15 | CTYPE_UINT, 16 | CTYPE_INT64, 17 | CTYPE_UINT64, 18 | CTYPE_FLOAT, 19 | CTYPE_BOOL, 20 | CTYPE_CHAR, 21 | CTYPE_STRING, 22 | CTYPE_LIST, 23 | CTYPE_TABLE, 24 | CTYPE_TUPLE, 25 | CTYPE_RANGE, 26 | CTYPE_FUNCTION, 27 | CTYPE_GENERATOR, 28 | CTYPE_ITERATOR, 29 | CTYPE_UNINFERRED, 30 | CTYPE_ANY_VARARG, 31 | CTYPE_ANY, 32 | CTYPE_UNSOLVED, 33 | CTYPE_STRUCT, 34 | CTYPE_OPTIONAL, 35 | CTYPE_ERROR, 36 | CTYPE_FILE, 37 | /* userdef */ 38 | CTYPE_USERDEF, 39 | /* type variable */ 40 | CTYPE_VARIABLE, 41 | }; 42 | 43 | enum typeimpl { 44 | T_SHOWABLE = 1 << 0, 45 | T_ITERABLE = 1 << 1, 46 | T_SUBSCRIPTABLE = 1 << 2, 47 | }; 48 | 49 | typedef struct Type Type; 50 | 51 | typedef char *(*type2str_t)(Type *); 52 | 53 | struct Type { 54 | enum ttype type; 55 | enum typeimpl impl; 56 | type2str_t tostring; 57 | bool optional; 58 | 59 | union { 60 | /* range */ 61 | struct { 62 | Type *ptr; 63 | }; 64 | /* tuple */ 65 | struct { 66 | Vector *tuple; 67 | }; 68 | /* list, table */ 69 | struct { 70 | Type *key; 71 | Type *val; 72 | }; 73 | /* function */ 74 | struct { 75 | Type *fnret; 76 | Vector *fnarg; 77 | }; 78 | /* struct */ 79 | struct { 80 | MxcStruct strct; 81 | char *name; 82 | }; 83 | /* variable */ 84 | struct { 85 | Type *real; 86 | char *vname; 87 | }; 88 | /* userdef type */ 89 | struct { 90 | char *uname; 91 | }; 92 | }; 93 | }; 94 | 95 | Type *new_type(enum ttype); 96 | Type *new_type_function(Vector *, Type *); 97 | Type *new_type_generator(Vector *, Type *); 98 | Type *new_type_iter(Type *); 99 | Type *new_type_list(Type *); 100 | Type *new_type_table(Type *, Type *); 101 | Type *new_type_unsolved(char *); 102 | Type *new_type_struct(MxcStruct); 103 | Type *new_typevariable(char *); 104 | Type *typevar(char *); 105 | bool has_tvar(Type *); 106 | 107 | Type *userdef_type(char *name, enum typeimpl impl); 108 | 109 | char *vec_tyfmt(Vector *ty); 110 | Type *typedup(Type *); 111 | 112 | bool same_type(Type *, Type *); 113 | bool is_struct(Type *); 114 | bool unsolved(Type *); 115 | Type *checktype(Type *, Type *); 116 | bool type_is(Type *, enum ttype); 117 | bool is_iterable(Type *); 118 | bool is_subscriptable(Type *t); 119 | Type *prune(Type *); 120 | 121 | #define mxc_none (&TypeNone) 122 | #define mxc_bool (&TypeBool) 123 | #define mxc_char (&TypeChar) 124 | #define mxc_int (&TypeInt) 125 | #define mxc_float (&TypeFloat) 126 | #define mxc_string (&TypeString) 127 | #define mxc_file (&TypeFile) 128 | #define mxc_any (&TypeAny) 129 | #define mxc_any_vararg (&TypeAnyVararg) 130 | 131 | #define typefmt(ty) (((Type *)ty)->tostring((Type *)ty)) 132 | 133 | extern Type TypeNone; 134 | extern Type TypeBool; 135 | extern Type TypeChar; 136 | extern Type TypeInt; 137 | extern Type TypeFloat; 138 | extern Type TypeString; 139 | extern Type TypeFile; 140 | extern Type TypeAny; 141 | extern Type TypeAnyVararg; 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef MXC_UTIL_H 2 | #define MXC_UTIL_H 3 | 4 | #include 5 | 6 | typedef struct Vector { 7 | void **data; 8 | uint16_t len; 9 | uint16_t reserved; 10 | } Vector; 11 | 12 | Vector *new_vector(void); 13 | Vector *new_vector_capa(int capa); 14 | void del_vector(Vector *); 15 | void vec_push(Vector *self, void *d); 16 | void *vec_pop(Vector *self); 17 | void *vec_last(Vector *self); 18 | 19 | int get_digit(int); 20 | char *read_file(const char *); 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_VM_H 2 | #define MAXC_VM_H 3 | 4 | #include 5 | #include "maxc.h" 6 | #include "context.h" 7 | #include "util.h" 8 | #include "literalpool.h" 9 | 10 | // #define DIRECT_THREADED 11 | 12 | extern int error_flag; 13 | 14 | typedef struct VM VM; 15 | struct VM { 16 | MContext *ctx; 17 | MxcValue *gvars; 18 | size_t ngvars; 19 | MxcValue *stackptr; 20 | MxcValue *stackbase; 21 | Vector *ltable; 22 | 23 | jmp_buf vm_end_jb; 24 | }; 25 | 26 | extern VM gvm; /* global VM */ 27 | 28 | void vm_open(mptr_t *, MxcValue *, int, Vector *, DebugInfo *); 29 | void vm_force_exit(int); 30 | int vm_run(void); 31 | void *vm_exec(VM *); 32 | void stackdump(char *); 33 | 34 | static inline VM *curvm() { 35 | return &gvm; 36 | } 37 | 38 | #define PUSH(ob) (*vm->stackptr++ = (ob)) 39 | #define POP() (*--vm->stackptr) 40 | #define TOP() (vm->stackptr[-1]) 41 | #define SETTOP(ob) (vm->stackptr[-1] = (ob)) 42 | 43 | extern MxcValue screg_a; 44 | extern MxcValue screg_b; 45 | 46 | enum stack_cache_state { 47 | SCXX = 0, 48 | SCAX = 1, 49 | SCBX = 2, 50 | SCBA = 3, 51 | SCAB = 4, 52 | }; 53 | 54 | extern enum stack_cache_state scstate; 55 | 56 | #define SC_NCACHE() ((scstate + 1) / 2) 57 | #define SC_TOPA() (scstate % 2) 58 | #define SC_TOPB() (!(scstate % 2)) 59 | 60 | #define CLEARCACHE() \ 61 | do { \ 62 | switch(scstate) { \ 63 | case SCXX: break; \ 64 | case SCAX: PUSH(screg_a); break; \ 65 | case SCBX: PUSH(screg_b); break; \ 66 | case SCBA: PUSH(screg_b); PUSH(screg_a); break; \ 67 | case SCAB: PUSH(screg_a); PUSH(screg_b); break; \ 68 | } \ 69 | scstate = SCXX; \ 70 | } while(0) 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/vmstate.h: -------------------------------------------------------------------------------- 1 | #ifndef MAXC_VMSTATE_H 2 | #define MAXC_VMSTATE_H 3 | 4 | #include "maxc.h" 5 | 6 | typedef struct VMState { 7 | enum RuntimeError err; 8 | } VMState; 9 | 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /lib/calendar.mxc: -------------------------------------------------------------------------------- 1 | use term; 2 | 3 | def put(year: int, month: int) { 4 | if month < 1 || 12 < month { 5 | return; 6 | } 7 | 8 | let month0 = month; 9 | month = month - 1; 10 | let t0 = [1,4,3,6,1,4,6,2,5,0,3,5]; 11 | let t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; 12 | 13 | if year % 400 == 0 { 14 | t1[1] = 29; 15 | } 16 | else if year % 4 == 0 && year % 100 != 0 { 17 | t1[1] = 29; 18 | } 19 | 20 | let mtable = [ 21 | "Jan", "Feb", "Mar", "Apr", 22 | "May", "Jun", "Jul", "Aug", 23 | "Sep", "Oct", "Nov", "Dec" 24 | ]; 25 | println("\t\t\t", term@Style.bold, mtable[month], " ", year, term@reset); 26 | println(term@Fg.red, term@Style.bold, "Sun \t", term@reset, "Mon \tTue \tWed \tThu \tFri \tSat"); 27 | 28 | let { 29 | w = if(month <= 1) year - 1 else year; 30 | w0 = w / 4; 31 | w1 = w / 100; 32 | w2 = w / 400; 33 | w3 = t0[month]; 34 | } 35 | 36 | w = (w + w0 - w1 + w2 + w3) % 7; 37 | 38 | if w > 0 { 39 | let d = 1; 40 | while d <= w { 41 | print(" ", "\t"); 42 | d = d + 1; 43 | } 44 | } 45 | 46 | let d1 = t1[month]; 47 | let d = 1; 48 | while d <= d1 { 49 | print(' ', d, '\t'); 50 | w = (w + 1) % 7; 51 | if w == 0 { 52 | println(""); 53 | } 54 | d = d + 1; 55 | } 56 | 57 | if w > 0 { 58 | println(""); 59 | } 60 | 61 | month = month + 1; 62 | } 63 | -------------------------------------------------------------------------------- /lib/math.mxc: -------------------------------------------------------------------------------- 1 | let { 2 | PI = 3.1415926535897932385; 3 | E = 2.7182818284590452353; 4 | } 5 | 6 | // 三角関数 7 | // sin(), cos(), tan(), asin(), acos(), atan() 8 | 9 | // 双曲線関数 10 | // sinh(), cosh(), tanh(), asinh(), acosh(), atanh() 11 | 12 | // 指数関数, 対数関数 13 | // exp(), exp2(), log(), log10(), log2() 14 | 15 | // 累乗, 冪根, 絶対値 16 | // pow(), sqrt(), cbrt(), hypot(), abs() 17 | def pow(x: int, n: int): int { 18 | let result = 1; 19 | while n > 1 { 20 | let { 21 | // キャストがあれば 22 | // n2 = (int)(n * 0.5); 23 | // の方が早そうだけどそこは内部の実装にも依りそう 24 | n2 = n / 2; 25 | i = n - (2 * n2); 26 | } 27 | if i > 0 { 28 | result = result * x; 29 | } 30 | x = x * x; 31 | n = n2; 32 | } 33 | return result * x; 34 | } 35 | 36 | def sqrt(x: float): float { 37 | if x < 0.0 || x == 0.0 { 38 | return 0.0; 39 | } 40 | let { 41 | before = x * 0.5; 42 | after = (before + x / before) * 0.5; 43 | d = before - after; 44 | } 45 | if d < 0.0 { 46 | d = -d; 47 | } 48 | while d > 0.000000001 { 49 | before = after; 50 | after = (before + x / before) * 0.5; 51 | d = before - after; 52 | } 53 | return after; 54 | } 55 | 56 | def abs(i: int): int { 57 | if i >= 0 { return i; } else { return -i; } 58 | } 59 | 60 | // 最近傍整数 61 | // ceil(), floor() 62 | 63 | // 剰余 64 | // fmod() 65 | 66 | // 線形補間 67 | // lerp() 68 | def lerp(a: float, b: float, t: float) = a + t * (b - a); 69 | -------------------------------------------------------------------------------- /lib/std.mxc: -------------------------------------------------------------------------------- 1 | iterator upto(from: int, to: int): int { 2 | while from <= to { 3 | yield from; 4 | from += 1; 5 | } 6 | } 7 | 8 | iterator downto(from: int, to: int): int { 9 | while from >= to { 10 | yield from; 11 | from -= 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/str.mxc: -------------------------------------------------------------------------------- 1 | def repeat(s: string, n: int): string { 2 | let i = 0; 3 | let res = ""; 4 | while i < n { 5 | res = res + s; 6 | i = i + 1; 7 | } 8 | return res; 9 | } 10 | 11 | def empty(s: string): bool = s.len == 0; 12 | -------------------------------------------------------------------------------- /lib/term.mxc: -------------------------------------------------------------------------------- 1 | object TermFgColor { 2 | red: string, 3 | green: string 4 | } 5 | 6 | object TermStyle { 7 | bold: string 8 | } 9 | 10 | let reset = "\e[0m"; 11 | 12 | let Fg = new TermFgColor{}; 13 | Fg.red = "\e[31m"; 14 | Fg.green = "\e[32m"; 15 | 16 | let Style = new TermStyle{}; 17 | Style.bold = "\e[1m"; 18 | -------------------------------------------------------------------------------- /src/compiler/ast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ast.h" 6 | #include "error/error.h" 7 | 8 | bool ast_isexpr(Ast *self) { 9 | if(!self) { 10 | return false; 11 | } 12 | 13 | switch(self->type) { 14 | case NDTYPE_NUM: 15 | case NDTYPE_BOOL: 16 | case NDTYPE_NULL: 17 | case NDTYPE_LIST: 18 | case NDTYPE_HASHTABLE: 19 | case NDTYPE_SUBSCR: 20 | case NDTYPE_TUPLE: 21 | case NDTYPE_FUNCCALL: 22 | case NDTYPE_ASSIGNMENT: 23 | case NDTYPE_VARIABLE: 24 | case NDTYPE_STRING: 25 | case NDTYPE_BINARY: 26 | case NDTYPE_MEMBER: 27 | case NDTYPE_DOTEXPR: 28 | case NDTYPE_STRUCTINIT: 29 | case NDTYPE_MODULEFUNCCALL: 30 | case NDTYPE_UNARY: 31 | return true; 32 | default: 33 | return false; 34 | } 35 | } 36 | 37 | bool node_is_number(Ast *a) { 38 | return a && a->type == NDTYPE_NUM; 39 | } 40 | 41 | NodeNumber *node_number_int(int64_t n, int lineno) { 42 | NodeNumber *node = (NodeNumber *)xmalloc(sizeof(NodeNumber)); 43 | 44 | ((Ast *)node)->type = NDTYPE_NUM; 45 | ((Ast *)node)->lineno = lineno; 46 | node->value = mval_int(n); 47 | CTYPE(node) = mxc_int; 48 | 49 | return node; 50 | } 51 | 52 | NodeNumber *node_number_big(MxcValue n, int lineno) { 53 | NodeNumber *node = (NodeNumber *)xmalloc(sizeof(NodeNumber)); 54 | 55 | ((Ast *)node)->type = NDTYPE_NUM; 56 | ((Ast *)node)->lineno = lineno; 57 | mgc_guard(n); 58 | node->value = n; 59 | CTYPE(node) = mxc_int; 60 | 61 | return node; 62 | } 63 | 64 | NodeNumber *node_number_float(double n, int lineno) { 65 | NodeNumber *node = (NodeNumber *)xmalloc(sizeof(NodeNumber)); 66 | 67 | ((Ast *)node)->type = NDTYPE_NUM; 68 | ((Ast *)node)->lineno = lineno; 69 | node->value = mval_float(n); 70 | CTYPE(node) = mxc_float; 71 | 72 | return node; 73 | } 74 | 75 | NodeBool *node_bool(bool b, int lineno) { 76 | NodeBool *node = xmalloc(sizeof(NodeBool)); 77 | 78 | ((Ast *)node)->type = NDTYPE_BOOL; 79 | ((Ast *)node)->lineno = lineno; 80 | CTYPE(node) = mxc_bool; 81 | node->boolean = b; 82 | 83 | return node; 84 | } 85 | 86 | NodeNull *node_null(int lineno) { 87 | NodeNull *node = xmalloc(sizeof(NodeNull)); 88 | 89 | ((Ast *)node)->type = NDTYPE_NULL; 90 | ((Ast *)node)->lineno = lineno; 91 | CTYPE(node) = mxc_any; 92 | 93 | return node; 94 | } 95 | 96 | NodeString *node_string(char *s, int lineno) { 97 | NodeString *node = xmalloc(sizeof(NodeString)); 98 | 99 | ((Ast *)node)->type = NDTYPE_STRING; 100 | ((Ast *)node)->lineno = lineno; 101 | CTYPE(node) = mxc_string; 102 | node->string = s; 103 | 104 | return node; 105 | } 106 | 107 | NodeList *node_list(Vector *e, size_t n, Ast *nelem, Ast *init, int lineno) { 108 | NodeList *node = xmalloc(sizeof(NodeList)); 109 | 110 | ((Ast *)node)->type = NDTYPE_LIST; 111 | ((Ast *)node)->lineno = lineno; 112 | CTYPE(node) = new_type(CTYPE_LIST); 113 | node->elem = e; 114 | node->nsize = n; 115 | node->nelem = nelem; 116 | node->init = init; 117 | 118 | return node; 119 | } 120 | 121 | NodeHashTable *node_hashtable(Vector *k, Vector *v, int lineno) { 122 | NodeHashTable *node = xmalloc(sizeof(NodeHashTable)); 123 | 124 | ((Ast *)node)->type = NDTYPE_HASHTABLE; 125 | ((Ast *)node)->lineno = lineno; 126 | node->key = k; 127 | node->val = v; 128 | 129 | return node; 130 | } 131 | 132 | NodeBinop *node_binary(enum BINOP op, Ast *left, Ast *right, int lineno) { 133 | NodeBinop *node = xmalloc(sizeof(NodeBinop)); 134 | 135 | ((Ast *)node)->type = NDTYPE_BINARY; 136 | ((Ast *)node)->lineno = lineno; 137 | node->op = op; 138 | node->left = left; 139 | node->right = right; 140 | node->impl = NULL; 141 | 142 | return node; 143 | } 144 | 145 | NodeMember *node_member(Ast *left, Ast *right, int lineno) { 146 | NodeMember *node = xmalloc(sizeof(NodeMember)); 147 | 148 | ((Ast *)node)->type = NDTYPE_MEMBER; 149 | ((Ast *)node)->lineno = lineno; 150 | node->left = left; 151 | node->right = right; 152 | 153 | return node; 154 | } 155 | 156 | NodeDotExpr *node_dotexpr(Ast *left, Ast *right, int lineno) { 157 | NodeDotExpr *node = xmalloc(sizeof(NodeDotExpr)); 158 | 159 | ((Ast *)node)->type = NDTYPE_DOTEXPR; 160 | ((Ast *)node)->lineno = lineno; 161 | node->left = left; 162 | node->right = right; 163 | node->t.objattr = node->t.member = node->t.fncall = 0; 164 | node->call = NULL; 165 | node->memb = NULL; 166 | node->offset = 0; 167 | node->attype = 0; 168 | 169 | return node; 170 | } 171 | 172 | NodeSubscript *node_subscript(Ast *l, Ast *i, int lineno) { 173 | NodeSubscript *node = xmalloc(sizeof(NodeSubscript)); 174 | 175 | ((Ast *)node)->type = NDTYPE_SUBSCR; 176 | ((Ast *)node)->lineno = lineno; 177 | node->ls = l; 178 | node->index = i; 179 | CTYPE(node) = NULL; 180 | 181 | return node; 182 | } 183 | 184 | NodeUnaop *node_unary(enum UNAOP op, Ast *e, int lineno) { 185 | NodeUnaop *node = xmalloc(sizeof(NodeUnaop)); 186 | ((Ast *)node)->type = NDTYPE_UNARY; 187 | ((Ast *)node)->lineno = lineno; 188 | node->op = op; 189 | node->expr = e; 190 | 191 | return node; 192 | } 193 | 194 | NodeFunction *node_function(NodeVariable *n, Ast *b, 195 | Vector *tyvars, Vector *args, bool iter, int lineno) { 196 | NodeFunction *node = xmalloc(sizeof(NodeFunction)); 197 | 198 | ((Ast *)node)->type = iter? NDTYPE_ITERATOR : NDTYPE_FUNCDEF; 199 | ((Ast *)node)->lineno = lineno; 200 | node->fnvar = n; 201 | node->block = b; 202 | node->lvars = new_vector(); 203 | node->args = args; 204 | node->typevars = tyvars; 205 | node->is_generic = tyvars ? true : false; 206 | node->op = -1; 207 | 208 | return node; 209 | } 210 | 211 | NodeFnCall *node_fncall(Ast *f, Vector *arg, int lineno) { 212 | NodeFnCall *node = xmalloc(sizeof(NodeFnCall)); 213 | 214 | ((Ast *)node)->type = NDTYPE_FUNCCALL; 215 | ((Ast *)node)->lineno = lineno; 216 | node->func = f; 217 | node->args = arg; 218 | 219 | return node; 220 | } 221 | 222 | NodeAssignment *node_assign(Ast *dst, Ast *src, int lineno) { 223 | NodeAssignment *node = xmalloc(sizeof(NodeAssignment)); 224 | 225 | ((Ast *)node)->type = NDTYPE_ASSIGNMENT; 226 | ((Ast *)node)->lineno = lineno; 227 | node->dst = dst; 228 | node->src = src; 229 | 230 | return node; 231 | } 232 | 233 | NodeVariable *node_variable(char *n, int flag, int lineno) { 234 | NodeVariable *node = xmalloc(sizeof(NodeVariable)); 235 | 236 | ((Ast *)node)->type = NDTYPE_VARIABLE; 237 | ((Ast *)node)->lineno = lineno; 238 | node->name = n; 239 | node->used = false; 240 | node->vattr = flag; 241 | CTYPE(node) = mxc_none; 242 | 243 | return node; 244 | } 245 | 246 | NodeVariable *node_variable_type(char *n, int flag, Type *t, int lineno) { 247 | NodeVariable *node = node_variable(n, flag, lineno); 248 | CTYPE(node) = t; 249 | 250 | return node; 251 | } 252 | 253 | NodeVardecl *node_vardecl(NodeVariable *v, Ast *init, Vector *block, int lineno) { 254 | NodeVardecl *node = xmalloc(sizeof(NodeVardecl)); 255 | ((Ast *)node)->type = NDTYPE_VARDECL; 256 | ((Ast *)node)->lineno = lineno; 257 | node->var = v; 258 | node->init = init; 259 | node->block = block; 260 | node->is_block = block ? true : false; 261 | 262 | return node; 263 | } 264 | 265 | NodeReturn *node_return(Ast *c, int lineno) { 266 | NodeReturn *node = xmalloc(sizeof(NodeReturn)); 267 | 268 | ((Ast *)node)->type = NDTYPE_RETURN; 269 | ((Ast *)node)->lineno = lineno; 270 | node->cont = c; 271 | 272 | return node; 273 | } 274 | 275 | NodeYield *node_yield(Ast *c, int lineno) { 276 | NodeYield *node = xmalloc(sizeof(NodeYield)); 277 | 278 | ((Ast *)node)->type = NDTYPE_YIELD; 279 | ((Ast *)node)->lineno = lineno; 280 | node->cont = c; 281 | 282 | return node; 283 | } 284 | 285 | NodeBreak *node_break(int lineno) { 286 | NodeBreak *node = xmalloc(sizeof(NodeBreak)); 287 | 288 | ((Ast *)node)->type = NDTYPE_BREAK; 289 | ((Ast *)node)->lineno = lineno; 290 | node->label = 0; 291 | 292 | return node; 293 | } 294 | 295 | NodeSkip *node_skip(int lineno) { 296 | NodeSkip *node = xmalloc(sizeof(NodeSkip)); 297 | 298 | ((Ast *)node)->type = NDTYPE_SKIP; 299 | ((Ast *)node)->lineno = lineno; 300 | 301 | return node; 302 | } 303 | 304 | NodeBreakPoint *node_breakpoint(int lineno) { 305 | NodeBreakPoint *node = xmalloc(sizeof(NodeBreakPoint)); 306 | 307 | ((Ast *)node)->type = NDTYPE_BREAKPOINT; 308 | ((Ast *)node)->lineno = lineno; 309 | 310 | return node; 311 | } 312 | 313 | NodeIf *node_if(Ast *c, Ast *t, Ast *e, bool i, int lineno) { 314 | NodeIf *node = xmalloc(sizeof(NodeIf)); 315 | 316 | ((Ast *)node)->type = i ? NDTYPE_EXPRIF : NDTYPE_IF; 317 | ((Ast *)node)->lineno = lineno; 318 | node->cond = c; 319 | node->then_s = t; 320 | node->else_s = e; 321 | node->isexpr = i; 322 | 323 | return node; 324 | } 325 | 326 | NodeFor *node_for(Vector *v, Ast *i, Ast *b, int lineno) { 327 | NodeFor *node = xmalloc(sizeof(NodeFor)); 328 | 329 | ((Ast *)node)->type = NDTYPE_FOR; 330 | ((Ast *)node)->lineno = lineno; 331 | node->vars = v; 332 | node->iter = i; 333 | node->body = b; 334 | 335 | return node; 336 | } 337 | 338 | NodeWhile *node_while(Ast *c, Ast *b, int lineno) { 339 | NodeWhile *node = xmalloc(sizeof(NodeWhile)); 340 | 341 | ((Ast *)node)->type = NDTYPE_WHILE; 342 | ((Ast *)node)->lineno = lineno; 343 | node->cond = c; 344 | node->body = b; 345 | 346 | return node; 347 | } 348 | 349 | NodeSwitch *node_switch(Ast *match, Vector *ecase, Vector *body, Ast *eelse, int lineno) { 350 | NodeSwitch *node = malloc(sizeof(NodeSwitch)); 351 | 352 | ((Ast *)node)->type = NDTYPE_SWITCH; 353 | ((Ast *)node)->lineno = lineno; 354 | node->match = match; 355 | node->ecase = ecase; 356 | node->body = body; 357 | node->eelse = eelse; 358 | 359 | return node; 360 | } 361 | 362 | NodeObject *node_object(char *name, Vector *decls, int lineno) { 363 | NodeObject *node = xmalloc(sizeof(NodeObject)); 364 | 365 | ((Ast *)node)->type = NDTYPE_OBJECT; 366 | ((Ast *)node)->lineno = lineno; 367 | node->tagname = name; 368 | node->decls = decls; 369 | 370 | return node; 371 | } 372 | 373 | NodeStructInit *node_struct_init(Type *t, Vector *f, Vector *i, int lineno) { 374 | NodeStructInit *node = xmalloc(sizeof(NodeStructInit)); 375 | 376 | ((Ast *)node)->type = NDTYPE_STRUCTINIT; 377 | ((Ast *)node)->lineno = lineno; 378 | node->tag = t; 379 | node->fields = f; 380 | node->inits = i; 381 | 382 | return node; 383 | } 384 | 385 | NodeBlock *node_block(Vector *c, int lineno) { 386 | NodeBlock *node = xmalloc(sizeof(NodeBlock)); 387 | 388 | ((Ast *)node)->type = NDTYPE_BLOCK; 389 | ((Ast *)node)->lineno = lineno; 390 | node->cont = c; 391 | 392 | return node; 393 | } 394 | 395 | NodeBlock *node_typedblock(Vector *c, int lineno) { 396 | NodeBlock *node = xmalloc(sizeof(NodeBlock)); 397 | 398 | ((Ast *)node)->type = NDTYPE_TYPEDBLOCK; 399 | ((Ast *)node)->lineno = lineno; 400 | node->cont = c; 401 | 402 | return node; 403 | } 404 | 405 | NodeModuleFuncCall *node_modulefunccall(Ast *l, Ast *i, int lineno) { 406 | NodeModuleFuncCall *node = xmalloc(sizeof(NodeModuleFuncCall)); 407 | 408 | ((Ast *)node)->type = NDTYPE_MODULEFUNCCALL; 409 | ((Ast *)node)->lineno = lineno; 410 | node->name = l; 411 | node->ident = i; 412 | 413 | return node; 414 | } 415 | 416 | NodeNameSpace *node_namespace(char *n, NodeBlock *b, int lineno, Vector *u) { 417 | NodeNameSpace *node = xmalloc(sizeof(NodeNameSpace)); 418 | 419 | ((Ast *)node)->type = NDTYPE_NAMESPACE; 420 | ((Ast *)node)->lineno = lineno; 421 | node->name = n; 422 | node->block = b; 423 | node->usenames = u; 424 | 425 | return node; 426 | } 427 | 428 | NodeAssert *node_assert(Ast *a, int lineno) { 429 | NodeAssert *node = xmalloc(sizeof(NodeAssert)); 430 | 431 | ((Ast *)node)->type = NDTYPE_ASSERT; 432 | ((Ast *)node)->lineno = lineno; 433 | node->cond = a; 434 | 435 | return node; 436 | } 437 | 438 | NoneNode_ nonenode = { 439 | { 440 | NDTYPE_NONENODE, 441 | 0, 442 | NULL, 443 | } 444 | }; 445 | 446 | -------------------------------------------------------------------------------- /src/compiler/bytecode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "bytecode.h" 3 | #include "literalpool.h" 4 | #include "maxc.h" 5 | #include "context.h" 6 | #include "vm.h" 7 | #include "error/error.h" 8 | 9 | #ifdef DIRECT_THREADED 10 | static const void **op_addr_table; 11 | 12 | void op_addr_table_init() { 13 | op_addr_table = (const void **)vm_exec(NULL); 14 | } 15 | #else 16 | void op_addr_table_init() { 17 | /* do nothing */ 18 | } 19 | #endif 20 | 21 | Bytecode *new_bytecode() { 22 | Bytecode *self = malloc(sizeof(Bytecode)); 23 | self->code = malloc(sizeof(mptr_t) * 64); 24 | self->len = 0; 25 | self->reserved = 64; 26 | 27 | return self; 28 | } 29 | 30 | static void push(Bytecode *self, mptr_t a) { 31 | if(self->len == self->reserved) { 32 | self->reserved *= 2; 33 | self->code = realloc(self->code, sizeof(mptr_t) * self->reserved); 34 | } 35 | 36 | self->code[self->len++] = a; 37 | } 38 | 39 | #ifdef DIRECT_THREADED 40 | void pushop(Bytecode *self, enum OPCODE op) { 41 | push(self, (mptr_t)op_addr_table[op * 5]); 42 | } 43 | #else 44 | void pushop(Bytecode *self, enum OPCODE op) { 45 | push(self, (mptr_t)(op + 1)); 46 | } 47 | #endif 48 | 49 | void pusharg(Bytecode *self, mptr_t a) { 50 | push(self, a); 51 | } 52 | 53 | void replace_int(size_t cpos, Bytecode *dst, int64_t src) { 54 | dst->code[cpos + 1] = (smptr_t)src; 55 | } 56 | 57 | static int32_t read_int32(mptr_t self[], size_t *pc) { // for Bytecode shower 58 | int32_t a = (smptr_t)self[(*pc)]; 59 | 60 | *pc += 1; 61 | 62 | return a; 63 | } 64 | 65 | void codedump(mptr_t a[], size_t *i, Vector *lt) { 66 | /* 67 | printf("%04ld ", *i); 68 | int c; 69 | 70 | switch(c = a[(*i)++]) { 71 | case OP_PUSH: { 72 | int key = read_int32(a, i); 73 | printf("push %d", key); 74 | break; 75 | } 76 | case OP_IPUSH: { 77 | int i32 = read_int32(a, i); 78 | printf("ipush %d", i32); 79 | break; 80 | } 81 | case OP_LPUSH: { 82 | int id = read_int32(a, i); 83 | printf("lpush %ld", ((Literal *)lt->data[id])->lnum); 84 | break; 85 | } 86 | case OP_PUSHCONST_0: printf("pushconst0"); break; 87 | case OP_PUSHCONST_1: printf("pushconst1"); break; 88 | case OP_PUSHCONST_2: printf("pushconst2"); break; 89 | case OP_PUSHCONST_3: printf("pushconst3"); break; 90 | case OP_PUSHTRUE: printf("pushtrue"); break; 91 | case OP_PUSHFALSE: printf("pushfalse"); break; 92 | case OP_PUSHNULL: printf("pushnull"); break; 93 | case OP_FPUSH: { 94 | int id = read_int32(a, i); 95 | printf("fpush %lf", ((Literal *)lt->data[id])->fnumber); 96 | break; 97 | } 98 | case OP_POP: printf("pop"); break; 99 | case OP_ADD: printf("add"); break; 100 | case OP_SUB: printf("sub"); break; 101 | case OP_MUL: printf("mul"); break; 102 | case OP_DIV: printf("div"); break; 103 | case OP_MOD: printf("mod"); break; 104 | case OP_LOGOR: printf("or"); break; 105 | case OP_LOGAND: printf("and"); break; 106 | case OP_EQ: printf("eq"); break; 107 | case OP_NOTEQ: printf("noteq"); break; 108 | case OP_LT: printf("lt"); break; 109 | case OP_LTE: printf("lte"); break; 110 | case OP_GT: printf("gt"); break; 111 | case OP_GTE: printf("gte"); break; 112 | case OP_FADD: printf("fadd"); break; 113 | case OP_FSUB: printf("fsub"); break; 114 | case OP_FMUL: printf("fmul"); break; 115 | case OP_FDIV: printf("fdiv"); break; 116 | case OP_FMOD: printf("fmod"); break; 117 | case OP_FLOGOR: printf("for"); break; 118 | case OP_FLOGAND: printf("fand"); break; 119 | case OP_FEQ: printf("feq"); break; 120 | case OP_FNOTEQ: printf("fnoteq"); break; 121 | case OP_FLT: printf("flt"); break; 122 | case OP_FLTE: printf("flte"); break; 123 | case OP_FGT: printf("fgt"); break; 124 | case OP_FGTE: printf("fgte"); break; 125 | case OP_INEG: printf("ineg"); break; 126 | case OP_FNEG: printf("fneg"); break; 127 | case OP_NOT: printf("not"); break; 128 | case OP_JMP: { 129 | int i32 = read_int32(a, i); 130 | printf("jmp %d", i32); 131 | break; 132 | } 133 | case OP_JMP_EQ: 134 | printf("jmpeq"); 135 | break; 136 | case OP_JMP_NOTEQ: { 137 | int i32 = read_int32(a, i); 138 | printf("jmpneq %d", i32); 139 | break; 140 | } 141 | case OP_STORE_LOCAL: { 142 | int id = read_int32(a, i); 143 | 144 | printf("store_local %d", id); 145 | 146 | break; 147 | } 148 | case OP_STORE_GLOBAL: { 149 | int id = read_int32(a, i); 150 | 151 | printf("store_global %d", id); 152 | 153 | break; 154 | } 155 | case OP_LISTSET: { 156 | int n = read_int32(a, i); 157 | 158 | printf("listset %d", n); 159 | 160 | break; 161 | } 162 | case OP_LISTSET_SIZE: printf("listset-size"); break; 163 | case OP_LISTLENGTH: printf("listlength"); break; 164 | case OP_SUBSCR: printf("subscr"); break; 165 | case OP_SUBSCR_STORE: printf("subscr_store"); break; 166 | case OP_STRINGSET: { 167 | int k = read_int32(a, i); 168 | printf("stringset %s", ((Literal *)lt->data[k])->str); 169 | break; 170 | } 171 | case OP_TABLESET: { 172 | int k = read_int32(a, i); 173 | printf("tableset %d", k); 174 | break; 175 | } 176 | case OP_TUPLESET: printf("tupleset"); break; 177 | case OP_FUNCTIONSET: { 178 | int k = read_int32(a, i); 179 | userfunction *f = ((Literal *)lt->data[k])->func; 180 | 181 | printf("funcset ->\n"); 182 | 183 | printf("length: %d\n", f->codesize); 184 | 185 | for(size_t n = 0; n < f->codesize;) { 186 | printf(" "); 187 | codedump(f->code, &n, lt); 188 | puts(""); 189 | } 190 | 191 | break; 192 | } 193 | case OP_ITERFN_SET: { 194 | int k = read_int32(a, i); 195 | userfunction *f = ((Literal *)lt->data[k])->func; 196 | 197 | printf("iterator set ->\n"); 198 | 199 | printf("length: %d\n", f->codesize); 200 | 201 | for(size_t n = 0; n < f->codesize; ) { 202 | printf(" "); 203 | codedump(f->code, &n, lt); 204 | puts(""); 205 | } 206 | 207 | break; 208 | } 209 | case OP_STRUCTSET: { 210 | int n = read_int32(a, i); 211 | 212 | printf("structset %d", n); 213 | 214 | break; 215 | } 216 | case OP_LOAD_GLOBAL: { 217 | int id = read_int32(a, i); 218 | 219 | printf("load_global %d", id); 220 | 221 | break; 222 | } 223 | case OP_LOAD_LOCAL: { 224 | int id = read_int32(a, i); 225 | 226 | printf("load_local %d", id); 227 | 228 | break; 229 | } 230 | case OP_RET: printf("ret"); break; 231 | case OP_YIELD: printf("yield"); break; 232 | case OP_CALL: { 233 | int n = read_int32(a, i); 234 | printf("call arg:%d", n); 235 | break; 236 | } 237 | case OP_END: printf("end"); break; 238 | case OP_MEMBER_LOAD: { 239 | int n = read_int32(a, i); 240 | 241 | printf("member-load %d", n); 242 | 243 | break; 244 | } 245 | case OP_MEMBER_STORE: { 246 | int n = read_int32(a, i); 247 | 248 | printf("member-store %d", n); 249 | 250 | break; 251 | } 252 | case OP_ITER: printf("get-iter"); break; 253 | case OP_ITER_NEXT: { 254 | int n = read_int32(a, i); 255 | 256 | printf("iter_next %d", n); 257 | 258 | break; 259 | } 260 | case OP_STRCAT: printf("strcat"); break; 261 | case OP_BREAKPOINT: printf("breakpoint"); break; 262 | case OP_ASSERT: printf("assert"); break; 263 | default: printf("!Error! %d", c); break; 264 | } 265 | */ 266 | } 267 | -------------------------------------------------------------------------------- /src/compiler/debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "maxc.h" 4 | #include "debug.h" 5 | 6 | DebugInfo *new_debuginfo(const char *fname, char *name) { 7 | DebugInfo *d = malloc(sizeof(DebugInfo)); 8 | d->filename = fname; 9 | d->name = name; 10 | d->pc_line_map = new_vector_capa(64); 11 | return d; 12 | } 13 | 14 | int curlineno(DebugInfo *d, mptr_t *pc, mptr_t *base) { 15 | int offset = pc - base - 1; 16 | return (int)(intptr_t)d->pc_line_map->data[offset]; 17 | } 18 | -------------------------------------------------------------------------------- /src/compiler/function.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "function.h" 3 | #include "bytecode.h" 4 | 5 | userfunction *new_userfunction(Bytecode *c, DebugInfo *d, size_t nlvars) { 6 | userfunction *u = malloc(sizeof(userfunction)); 7 | u->code = c->code; 8 | u->codesize = c->len; 9 | u->nlvars = nlvars; 10 | u->d = d; 11 | 12 | return u; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /src/compiler/lexer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "lexer.h" 7 | #include "error/error.h" 8 | #include "maxc.h" 9 | #include "util.h" 10 | #include "token.h" 11 | 12 | char *strndup(const char *, size_t); 13 | 14 | #define STEP() \ 15 | do { \ 16 | ++i; \ 17 | ++col; \ 18 | } while(0) 19 | #define PREV() \ 20 | do { \ 21 | --i; \ 22 | --col; \ 23 | } while(0) 24 | 25 | #define TWOCHARS(c1, c2) (src[i] == c1 && src[i + 1] == c2) 26 | 27 | static void scan(Vector *, const char *, const char *); 28 | 29 | Vector *lexer_run(const char *src, const char *fname) { 30 | Vector *tokens = new_vector(); 31 | scan(tokens, src, fname); 32 | 33 | return tokens; 34 | } 35 | 36 | static char escaped[256] = { 37 | ['a'] = '\a', 38 | ['b'] = '\b', 39 | ['f'] = '\f', 40 | ['n'] = '\n', 41 | ['r'] = '\r', 42 | ['t'] = '\t', 43 | ['v'] = '\v', 44 | ['\\'] = '\\', 45 | ['\''] = '\'', 46 | ['\"'] = '\"', 47 | ['e'] = '\033', 48 | ['E'] = '\033' 49 | }; 50 | 51 | char *escapedstrdup(const char *s, size_t n) { 52 | char buf[n+1]; 53 | int len = 0; 54 | char c; 55 | for(size_t i = 0; i < n; i++, s++) { 56 | if(*s == '\\') { 57 | i++; 58 | c = escaped[(int)*++s]; 59 | } 60 | else { 61 | c = *s; 62 | } 63 | buf[len++] = c; 64 | } 65 | char *new = malloc(sizeof(char) * (len + 1)); 66 | memset(new, 0, sizeof(char) * (len + 1)); 67 | strncpy(new, buf, sizeof(char) * len); 68 | 69 | return new; 70 | } 71 | 72 | static void scan(Vector *tk, const char *src, const char *fname) { 73 | int line = 1; 74 | int col = 1; 75 | size_t src_len = strlen(src); 76 | 77 | for(size_t i = 0; i < src_len; i++, col++) { 78 | if(isdigit(src[i])) { 79 | SrcPos start = cur_srcpos(fname, line, col); 80 | const char *buf = src + i; 81 | bool isdot = false; 82 | 83 | int len = 0; 84 | for(; isdigit(src[i]) || (src[i] == '.' && src[i+1] != '.'); i++, col++) { 85 | len++; 86 | 87 | if(src[i] == '.') { 88 | if(isdot) break; 89 | isdot = true; 90 | } 91 | } 92 | PREV(); 93 | if(src[i] == '.') { 94 | /* 95 | * 30.fibo() 96 | * ^ 97 | */ 98 | PREV(); 99 | len--; 100 | } 101 | SrcPos end = cur_srcpos(fname, line, col); 102 | char *str = strndup(buf, len); 103 | token_push_num(tk, str, len, start, end); 104 | } 105 | else if(isalpha(src[i]) || src[i] == '_') { 106 | /* (alpha|_) (alpha|digit|_)* */ 107 | const char *ident_s = src + i; 108 | SrcPos start = cur_srcpos(fname, line, col); 109 | int len = 0; 110 | for(; isalpha(src[i]) || isdigit(src[i]) || src[i] == '_'; i++, col++) { 111 | len++; 112 | } 113 | if(len > 255) { 114 | error("too long identifer"); 115 | } 116 | 117 | PREV(); 118 | char *ident = strndup(ident_s, len); 119 | SrcPos end = cur_srcpos(fname, line, col); 120 | token_push_ident(tk, ident, len, start, end); 121 | } 122 | else if(TWOCHARS('&', '&') || TWOCHARS('|', '|') || 123 | TWOCHARS('.', '.') || TWOCHARS('>', '>') || 124 | TWOCHARS('=', '>') || TWOCHARS('<', '<') || 125 | TWOCHARS('-', '>')) { 126 | SrcPos s = cur_srcpos(fname, line, col); 127 | 128 | enum tkind kind = tk_char2(src[i], src[i + 1]); 129 | STEP(); 130 | 131 | SrcPos e = cur_srcpos(fname, line, col); 132 | token_push_symbol(tk, kind, 2, s, e); 133 | } 134 | else if((src[i] == '/') && (src[i + 1] == '/')) { 135 | for(; src[i] != '\n' && src[i] != '\0'; i++, col++); 136 | 137 | PREV(); 138 | continue; 139 | } 140 | else if(strchr("(){}&|[]:.,?;@#", src[i])) { 141 | SrcPos loc = cur_srcpos(fname, line, col); 142 | 143 | enum tkind kind = tk_char1(src[i]); 144 | token_push_symbol(tk, kind, 1, loc, loc); 145 | } 146 | else if(strchr("=<>!+-*/%", src[i])) { 147 | SrcPos s = cur_srcpos(fname, line, col); 148 | SrcPos e; 149 | 150 | enum tkind kind; 151 | if(src[i + 1] == '=') { 152 | kind = tk_char2(src[i], src[i + 1]); 153 | STEP(); 154 | e = cur_srcpos(fname, line, col); 155 | token_push_symbol(tk, kind, 2, s, e); 156 | } 157 | else { 158 | kind = tk_char1(src[i]); 159 | e = cur_srcpos(fname, line, col); 160 | token_push_symbol(tk, kind, 1, s, e); 161 | } 162 | } 163 | else if(src[i] == '\"' || src[i] == '\'') { 164 | char quote = src[i]; 165 | SrcPos s = cur_srcpos(fname, line, col); 166 | STEP(); 167 | const char *buf = src + i; 168 | int len = 0; 169 | for(; src[i] != quote; i++, col++) { 170 | if(src[i] == '\n') { 171 | error("missing character:`%c`", quote); 172 | break; 173 | } 174 | len++; 175 | } 176 | SrcPos e = cur_srcpos(fname, line, col); 177 | 178 | char *str = escapedstrdup(buf, len); 179 | token_push_string(tk, str, len, s, e); 180 | } 181 | else if(src[i] == '`') { 182 | SrcPos s = cur_srcpos(fname, line, col); 183 | STEP(); 184 | const char *buf = src + i; 185 | 186 | int len = 0; 187 | for(; src[i] != '`'; i++, col++) { 188 | len++; 189 | 190 | if(src[i] == '\0') { 191 | error("missing charcter:'`'"); 192 | return; 193 | } 194 | } 195 | 196 | char *str = strndup(buf, len); 197 | SrcPos e = cur_srcpos(fname, line, col); 198 | 199 | token_push_backquote_lit(tk, str, len, s, e); 200 | } 201 | else if(isblank(src[i])) { 202 | continue; 203 | } 204 | else if(src[i] == '\n') { 205 | line++; 206 | col = 0; 207 | continue; 208 | } 209 | else { 210 | error("invalid syntax: \" %c \"", src[i]); 211 | break; 212 | } 213 | } 214 | 215 | SrcPos eof = cur_srcpos(fname, ++line, col); 216 | token_push_end(tk, eof, eof); 217 | } 218 | -------------------------------------------------------------------------------- /src/compiler/namespace.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "internal.h" 4 | #include "namespace.h" 5 | 6 | Vector *namespace_table = NULL; 7 | 8 | static Namespace *new_namespace(char *n, Vector *l) { 9 | Namespace *ns = xmalloc(sizeof(Namespace)); 10 | ns->name = n; 11 | ns->vars = l; 12 | 13 | return ns; 14 | } 15 | 16 | void reg_namespace(char *n, Vector *l) { 17 | if(!namespace_table) { 18 | namespace_table = new_vector(); 19 | } 20 | Namespace *ns = new_namespace(n, l); 21 | 22 | vec_push(namespace_table, ns); 23 | } 24 | 25 | Vector *search_namespace(char *name) { 26 | if(!namespace_table) { 27 | return NULL; 28 | } 29 | 30 | for(size_t i = 0; i < namespace_table->len; ++i) { 31 | Namespace *cur = (Namespace *)namespace_table->data[i]; 32 | if(strcmp(cur->name, name) == 0) { 33 | return cur->vars; 34 | } 35 | } 36 | 37 | return NULL; 38 | } 39 | -------------------------------------------------------------------------------- /src/compiler/operator.c: -------------------------------------------------------------------------------- 1 | #include "operator.h" 2 | #include "sema.h" 3 | #include "error/error.h" 4 | #include "type.h" 5 | #include "object/mstr.h" 6 | 7 | struct moperator { 8 | enum MXC_OPERATOR kind; 9 | int op; 10 | Type *operand2; 11 | Type *ret; 12 | void *func; 13 | char *opname; 14 | }; 15 | 16 | static struct moperator opdefs_integer[] = { 17 | /* kind */ /* ope */ /* ope2 */ /* ret */ /* fn *//* opname */ 18 | {OPE_BINARY, BIN_ADD, mxc_int, mxc_int, NULL, "+"}, 19 | {OPE_BINARY, BIN_SUB, mxc_int, mxc_int, NULL, "-"}, 20 | {OPE_BINARY, BIN_MUL, mxc_int, mxc_int, NULL, "*"}, 21 | {OPE_BINARY, BIN_DIV, mxc_int, mxc_int, NULL, "/"}, 22 | {OPE_BINARY, BIN_MOD, mxc_int, mxc_int, NULL, "%"}, 23 | {OPE_BINARY, BIN_EQ, mxc_int, mxc_bool, NULL, "=="}, 24 | {OPE_BINARY, BIN_NEQ, mxc_int, mxc_bool, NULL, "!="}, 25 | {OPE_BINARY, BIN_LT, mxc_int, mxc_bool, NULL, "<"}, 26 | {OPE_BINARY, BIN_LTE, mxc_int, mxc_bool, NULL, "<="}, 27 | {OPE_BINARY, BIN_GT, mxc_int, mxc_bool, NULL, ">"}, 28 | {OPE_BINARY, BIN_GTE, mxc_int, mxc_bool, NULL, ">="}, 29 | {OPE_BINARY, BIN_LAND, mxc_int, mxc_bool, NULL, "and"}, 30 | {OPE_BINARY, BIN_LOR, mxc_int, mxc_bool, NULL, "or"}, 31 | {OPE_BINARY, BIN_LSHIFT,mxc_int, mxc_int, NULL, "<<"}, 32 | {OPE_BINARY, BIN_RSHIFT,mxc_int, mxc_int, NULL, ">>"}, 33 | {OPE_BINARY, BIN_BXOR, mxc_int, mxc_int, NULL, "xor"}, 34 | {OPE_UNARY, UNA_INC, NULL, mxc_int, NULL, "++"}, 35 | {OPE_UNARY, UNA_DEC, NULL, mxc_int, NULL, "--"}, 36 | {OPE_UNARY, UNA_MINUS, NULL, mxc_int, NULL, "-"}, 37 | {-1, -1, NULL, NULL, NULL, NULL} 38 | }; 39 | 40 | static struct moperator opdefs_boolean[] = { 41 | /* kind */ /* ope */ /* ope2 */ /* ret */ /* fn *//* opname */ 42 | {OPE_BINARY, BIN_EQ, mxc_bool, mxc_bool, NULL, "=="}, 43 | {OPE_BINARY, BIN_NEQ, mxc_bool, mxc_bool, NULL, "!="}, 44 | {OPE_BINARY, BIN_LAND, mxc_bool, mxc_bool, NULL, "and"}, 45 | {OPE_BINARY, BIN_LOR, mxc_bool, mxc_bool, NULL, "or"}, 46 | {OPE_UNARY, UNA_NOT, NULL, mxc_bool, NULL, "!"}, 47 | {-1, -1, NULL, NULL, NULL, NULL}, 48 | }; 49 | 50 | static struct moperator opdefs_float[] = { 51 | /* kind */ /* ope */ /* ope2 */ /* ret */ /* fn *//* opname */ 52 | {OPE_BINARY, BIN_ADD, mxc_float, mxc_float, NULL, "+"}, 53 | {OPE_BINARY, BIN_SUB, mxc_float, mxc_float, NULL, "-"}, 54 | {OPE_BINARY, BIN_MUL, mxc_float, mxc_float, NULL, "*"}, 55 | {OPE_BINARY, BIN_DIV, mxc_float, mxc_float, NULL, "/"}, 56 | {OPE_BINARY, BIN_EQ, mxc_float, mxc_bool, NULL, "=="}, 57 | {OPE_BINARY, BIN_NEQ, mxc_float, mxc_bool, NULL, "!="}, 58 | {OPE_BINARY, BIN_LT, mxc_float, mxc_bool, NULL, "<"}, 59 | {OPE_BINARY, BIN_LTE, mxc_float, mxc_bool, NULL, "<="}, 60 | {OPE_BINARY, BIN_GT, mxc_float, mxc_bool, NULL, ">"}, 61 | {OPE_BINARY, BIN_GTE, mxc_float, mxc_bool, NULL, ">="}, 62 | {OPE_UNARY, UNA_MINUS, NULL, mxc_float, NULL, "-"}, 63 | {-1, -1, NULL, NULL, NULL, NULL}, 64 | }; 65 | 66 | static struct moperator opdefs_string[] = { 67 | /* kind */ /* ope */ /* ope2 */ /* ret */ /* fn */ /* opname */ 68 | {OPE_BINARY, BIN_ADD, mxc_string, mxc_string, NULL, "+"}, 69 | {OPE_BINARY, BIN_EQ, mxc_string, mxc_bool, NULL, "=="}, 70 | {-1, -1, NULL, NULL, NULL, NULL}, 71 | }; 72 | 73 | static struct moperator *operator_definition(Type *ope1) { 74 | switch(ope1->type) { 75 | case CTYPE_INT: return opdefs_integer; 76 | case CTYPE_BOOL: return opdefs_boolean; 77 | case CTYPE_FLOAT: return opdefs_float; 78 | case CTYPE_STRING: return opdefs_string; 79 | default: return NULL; 80 | } 81 | } 82 | 83 | Type *operator_type(enum MXC_OPERATOR kind, 84 | int op, 85 | Type *ope1, 86 | Type *ope2) { 87 | struct moperator *defs = operator_definition(ope1); 88 | if(!defs) 89 | return NULL; 90 | 91 | if(op == BIN_QUESTION) 92 | return checktype(ope1, ope2); 93 | 94 | struct moperator *cur; 95 | for(int i = 0; defs[i].kind != -1; ++i) { 96 | cur = &defs[i]; 97 | 98 | if(cur->kind != kind || cur->op != op) 99 | continue; 100 | if(ope2 && !same_type(cur->operand2, ope2)) 101 | continue; 102 | 103 | return cur->ret; 104 | } 105 | return NULL; 106 | } 107 | 108 | enum BINOP op_char1(char c) { 109 | switch(c) { 110 | case '+': return BIN_ADD; 111 | case '-': return BIN_SUB; 112 | case '*': return BIN_MUL; 113 | case '/': return BIN_DIV; 114 | case '%': return BIN_MOD; 115 | case '<': return BIN_LT; 116 | case '>': return BIN_GT; 117 | default : return -1; 118 | } 119 | } 120 | 121 | enum BINOP op_char2(char c1, char c2) { 122 | switch(c1) { 123 | case '=': 124 | switch(c2) { 125 | case '=': 126 | return BIN_EQ; 127 | } 128 | break; 129 | case '<': 130 | switch(c2) { 131 | case '=': 132 | return BIN_LTE; 133 | case '<': 134 | return BIN_LSHIFT; 135 | } 136 | break; 137 | case '>': 138 | switch(c2) { 139 | case '=': 140 | return BIN_GTE; 141 | case '>': 142 | return BIN_RSHIFT; 143 | } 144 | break; 145 | case '!': 146 | switch(c2) { 147 | case '=': 148 | return BIN_NEQ; 149 | } 150 | break; 151 | default: 152 | return -1; 153 | } 154 | } 155 | 156 | 157 | char *operator_dump(enum MXC_OPERATOR k, int n) { 158 | if(k == OPE_BINARY) { 159 | switch(n) { 160 | case BIN_ADD: return "+"; 161 | case BIN_SUB: return "-"; 162 | case BIN_MUL: return "*"; 163 | case BIN_DIV: return "/"; 164 | case BIN_MOD: return "%"; 165 | case BIN_EQ: return "=="; 166 | case BIN_NEQ: return "!="; 167 | case BIN_LT: return "<"; 168 | case BIN_LTE: return "<="; 169 | case BIN_GT: return ">"; 170 | case BIN_GTE: return ">="; 171 | case BIN_LAND: return "&&"; 172 | case BIN_LOR: return "||"; 173 | case BIN_LSHIFT: return "<<"; 174 | case BIN_RSHIFT: return ">>"; 175 | case BIN_QUESTION: return "?"; 176 | default: return "error!"; 177 | } 178 | } 179 | else if(k == OPE_UNARY) { 180 | switch(n) { 181 | case UNA_INC: return "++"; 182 | case UNA_DEC: return "--"; 183 | case UNA_PLUS: return "+"; 184 | case UNA_MINUS: return "-"; 185 | case UNA_NOT: return "!"; 186 | default: return "error!"; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/compiler/scope.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "scope.h" 5 | #include "ast.h" 6 | #include "error/error.h" 7 | 8 | Scope *make_scope(Scope *s, enum scopetype ty) { 9 | Scope *n = malloc(sizeof(Scope)); 10 | n->parent = s; 11 | n->vars = new_vector(); 12 | n->userdef_type = new_vector(); 13 | 14 | if(ty == FUNCSCOPE) 15 | n->fscope_vars = new_vector(); 16 | else if(ty == BLOCKSCOPE) 17 | n->fscope_vars = s->fscope_vars; 18 | 19 | n->type = ty; 20 | 21 | if(!s || (s->fscope_gbl && ty == BLOCKSCOPE)) 22 | n->fscope_gbl = true; 23 | else 24 | n->fscope_gbl = false; 25 | 26 | n->err = s? s->err : 0; 27 | 28 | return n; 29 | } 30 | 31 | Scope *scope_escape(Scope *s) { 32 | Scope *parent = s->parent; 33 | /* 34 | for(int i = 0; i < s->vars->len; i++) { 35 | NodeVariable *v = (NodeVariable *)s->vars->data[i]; 36 | if(!v->used && !v->isbuiltin) { 37 | warn("unused variable: %s", v->name); 38 | } 39 | } 40 | */ 41 | parent->err = s->err; 42 | 43 | return parent; 44 | } 45 | 46 | int chk_var_conflict(Scope *s, NodeVariable *v) { 47 | Vector *vars = s->vars; 48 | 49 | for(int i = 0; i < vars->len; ++i) { 50 | NodeVariable *cur = (NodeVariable *)vars->data[i]; 51 | 52 | if(strcmp(cur->name, v->name) == 0) { 53 | return 1; 54 | } 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | NodeVariable *searchbyname(Scope *s, char *name) { 61 | Vector *vars = s->vars; 62 | 63 | for(int i = 0; i < vars->len; ++i) { 64 | NodeVariable *cur = (NodeVariable *)vars->data[i]; 65 | 66 | if(strcmp(cur->name, name) == 0) { 67 | return cur; 68 | } 69 | } 70 | 71 | return NULL; 72 | } 73 | 74 | void varlist_show(Scope *s) { 75 | log_dbg("varlist show: "); 76 | for(int i = 0; i < s->vars->len; ++i) { 77 | NodeVariable *cur = (NodeVariable *)s->vars->data[i]; 78 | if(cur) { 79 | log_dbg("%s ", cur->name); 80 | } 81 | else { 82 | log_dbg("null "); 83 | } 84 | } 85 | log_dbg("\n"); 86 | } 87 | 88 | void scope_push_var(Scope *scope, NodeVariable *var) { 89 | vec_push(scope->vars, var); 90 | vec_push(scope->fscope_vars, var); 91 | } 92 | 93 | void scope_reg_userdefty(Scope *scope, Type *ty) { 94 | vec_push(scope->userdef_type, ty); 95 | } 96 | 97 | size_t var_assign_id(Scope *s) { 98 | size_t id = 0; 99 | for(size_t i = 0; i < s->fscope_vars->len; ++i) { 100 | NodeVariable *cur = (NodeVariable *)s->fscope_vars->data[i]; 101 | cur->vid = id++; 102 | } 103 | 104 | return id; 105 | } 106 | -------------------------------------------------------------------------------- /src/compiler/struct.c: -------------------------------------------------------------------------------- 1 | #include "struct.h" 2 | 3 | MxcStruct new_cstruct(char *name, struct NodeVariable **f, size_t nf) { 4 | return (MxcStruct){name, f, nf}; 5 | } 6 | -------------------------------------------------------------------------------- /src/compiler/token.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "token.h" 5 | #include "error/error.h" 6 | #include "maxc.h" 7 | #include "operator.h" 8 | 9 | static enum tkind ident2kw(char *); 10 | 11 | struct keywordmap { 12 | char *key; 13 | enum tkind kind; 14 | } mxc_kwmap[] = { 15 | #define KEYWORD(s, k) {s, k}, 16 | #define KEYWORD_ALIAS(s, k) {s, k}, 17 | #include "keyword.h" 18 | #undef KEYWORD 19 | #undef KEYWORD_ALIAS 20 | }; 21 | 22 | enum tkind tk_char1(int c) { 23 | switch(c) { 24 | case '+': return TKIND_Plus; 25 | case '-': return TKIND_Minus; 26 | case '*': return TKIND_Asterisk; 27 | case '/': return TKIND_Div; 28 | case '%': return TKIND_Mod; 29 | case '(': return TKIND_Lparen; 30 | case ')': return TKIND_Rparen; 31 | case '{': return TKIND_Lbrace; 32 | case '}': return TKIND_Rbrace; 33 | case '[': return TKIND_Lboxbracket; 34 | case ']': return TKIND_Rboxbracket; 35 | case ',': return TKIND_Comma; 36 | case ':': return TKIND_Colon; 37 | case ';': return TKIND_Semicolon; 38 | case '.': return TKIND_Dot; 39 | case '<': return TKIND_Lt; 40 | case '>': return TKIND_Gt; 41 | case '=': return TKIND_Assign; 42 | case '!': return TKIND_Bang; 43 | case '?': return TKIND_Question; 44 | case '@': return TKIND_Atmark; 45 | case '#': return TKIND_Hash; 46 | default: 47 | panic("unknown symbol: %c", c); 48 | } 49 | } 50 | 51 | enum tkind tk_char2(int c1, int c2) { 52 | switch(c1) { 53 | case '=': 54 | switch(c2) { 55 | case '=': 56 | return TKIND_Eq; 57 | case '>': 58 | return TKIND_FatArrow; 59 | } 60 | break; 61 | case '<': 62 | switch(c2) { 63 | case '=': 64 | return TKIND_Lte; 65 | case '<': 66 | return TKIND_Lshift; 67 | } 68 | break; 69 | case '>': 70 | switch(c2) { 71 | case '=': 72 | return TKIND_Gte; 73 | case '>': 74 | return TKIND_Rshift; 75 | } 76 | break; 77 | case '!': 78 | switch(c2) { 79 | case '=': 80 | return TKIND_Neq; 81 | } 82 | break; 83 | case '+': 84 | switch(c2) { 85 | case '+': 86 | return TKIND_Inc; 87 | case '=': 88 | return TKIND_PlusAs; 89 | } 90 | break; 91 | case '-': 92 | switch(c2) { 93 | case '-': 94 | return TKIND_Dec; 95 | case '=': 96 | return TKIND_MinusAs; 97 | case '>': 98 | return TKIND_Arrow; 99 | } 100 | break; 101 | case '*': 102 | switch(c2) { 103 | case '=': 104 | return TKIND_AsteriskAs; 105 | } 106 | break; 107 | case '&': 108 | switch(c2) { 109 | case '&': 110 | return TKIND_LogAnd; 111 | } 112 | break; 113 | case '|': 114 | switch(c2) { 115 | case '|': 116 | return TKIND_LogOr; 117 | } 118 | break; 119 | case '/': 120 | switch(c2) { 121 | case '=': 122 | return TKIND_DivAs; 123 | } 124 | break; 125 | case '%': 126 | switch(c2) { 127 | case '=': 128 | return TKIND_ModAs; 129 | } 130 | break; 131 | case '.': 132 | switch(c2) { 133 | case '.': 134 | return TKIND_DotDot; 135 | } 136 | break; 137 | default: 138 | error("internal error: %c%c", c1, c2); 139 | return -1; 140 | } 141 | } 142 | 143 | char *tk2str(Token *tk) { 144 | switch(tk->kind) { 145 | case TKIND_End: return "End"; 146 | case TKIND_Num: 147 | case TKIND_String: 148 | case TKIND_Char: 149 | case TKIND_Identifer: return tk->value; 150 | default: return tkind2str(tk->kind); 151 | } 152 | } 153 | 154 | char *tkind2str(enum tkind tk) { 155 | switch(tk) { 156 | case TKIND_End: return "End"; 157 | case TKIND_Num: return "Number"; 158 | case TKIND_String: return "String"; 159 | case TKIND_Char: return "Char"; 160 | case TKIND_Identifer: return "Identifer"; 161 | #define KEYWORD(s, k) case k: return s; 162 | #define KEYWORD_ALIAS(s, k) 163 | #include "keyword.h" 164 | #undef KEYWORD 165 | #undef KEYWORD_ALIAS 166 | case TKIND_Lparen: return "("; 167 | case TKIND_Rparen: return ")"; 168 | case TKIND_Lbrace: return "{"; 169 | case TKIND_Rbrace: return "}"; 170 | case TKIND_Lboxbracket: return "["; 171 | case TKIND_Rboxbracket: return "]"; 172 | case TKIND_Comma: return ","; 173 | case TKIND_Colon: return ":"; 174 | case TKIND_Dot: return "."; 175 | case TKIND_DotDot: return ".."; 176 | case TKIND_Semicolon: return ";"; 177 | case TKIND_Arrow: return "->"; 178 | case TKIND_FatArrow: return "=>"; 179 | case TKIND_Inc: return "++"; 180 | case TKIND_Dec: return "--"; 181 | case TKIND_Plus: return "+"; 182 | case TKIND_Minus: return "-"; 183 | case TKIND_Asterisk: return "*"; 184 | case TKIND_Div: return "/"; 185 | case TKIND_Mod: return "%"; 186 | case TKIND_Eq: return "=="; 187 | case TKIND_Neq: return "!="; 188 | case TKIND_Lt: return "<"; 189 | case TKIND_Lte: return "<="; 190 | case TKIND_Gt: return ">"; 191 | case TKIND_Gte: return ">="; 192 | case TKIND_LogAnd: return "&&"; 193 | case TKIND_LogOr: return "||"; 194 | case TKIND_Lshift: return "<<"; 195 | case TKIND_Rshift: return ">>"; 196 | case TKIND_Assign: return "="; 197 | case TKIND_Bang: return "!"; 198 | case TKIND_Question: return "?"; 199 | default: return "error"; 200 | } 201 | } 202 | 203 | static Token *newtoken(enum tkind kind, 204 | char *value, 205 | uint8_t len, 206 | SrcPos s, 207 | SrcPos e) { 208 | Token *self = malloc(sizeof(Token)); 209 | 210 | self->kind = kind; 211 | self->value = value; 212 | self->len = len; 213 | self->start = s; 214 | self->end = e; 215 | 216 | return self; 217 | } 218 | 219 | static Token *newtoken_ch(char c, SrcPos s, SrcPos e) { 220 | Token *self = malloc(sizeof(Token)); 221 | self->kind = TKIND_Char; 222 | self->cont = c; 223 | self->len = 1; 224 | self->start = s; 225 | self->end = e; 226 | 227 | return self; 228 | } 229 | 230 | static Token *newtoken_bq(enum tkind cont, uint8_t len, SrcPos s, SrcPos e) { 231 | Token *self = malloc(sizeof(Token)); 232 | self->kind = TKIND_BQLIT; 233 | self->cont = cont; 234 | self->len = len; 235 | self->start = s; 236 | self->end = e; 237 | 238 | return self; 239 | } 240 | 241 | static Token *newtoken_sym(enum tkind kind, 242 | uint8_t len, 243 | SrcPos s, 244 | SrcPos e) { 245 | Token *self = malloc(sizeof(Token)); 246 | 247 | self->kind = kind; 248 | self->value = ""; 249 | self->len = len; 250 | self->start = s; 251 | self->end = e; 252 | 253 | return self; 254 | } 255 | 256 | static Token *newtoken_end(SrcPos s, SrcPos e) { 257 | Token *self = malloc(sizeof(Token)); 258 | 259 | self->kind = TKIND_End; 260 | self->value = ""; 261 | self->len = 1; 262 | self->start = s; 263 | self->end = e; 264 | 265 | return self; 266 | } 267 | 268 | void token_push_num(Vector *self, char *value, uint8_t len, SrcPos s, SrcPos e) { 269 | Token *tk = newtoken(TKIND_Num, value, len, s, e); 270 | 271 | vec_push(self, tk); 272 | } 273 | 274 | void token_push_ident(Vector *self, char *val, uint8_t len, SrcPos s, SrcPos e) { 275 | enum tkind kind = ident2kw(val); 276 | 277 | Token *tk = newtoken(kind, val, len, s, e); 278 | 279 | vec_push(self, tk); 280 | } 281 | 282 | void token_push_symbol( 283 | Vector *self, 284 | enum tkind kind, 285 | uint8_t len, 286 | SrcPos s, 287 | SrcPos e 288 | ) { 289 | Token *tk = newtoken_sym(kind, len, s, e); 290 | 291 | vec_push(self, tk); 292 | } 293 | 294 | void token_push_string(Vector *self, char *str, uint32_t len, SrcPos s, SrcPos e) { 295 | Token *tk = newtoken(TKIND_String, str, len, s, e); 296 | 297 | vec_push(self, tk); 298 | } 299 | 300 | void token_push_char(Vector *self, char c, SrcPos s, SrcPos e) { 301 | vec_push(self, newtoken_ch(c, s, e)); 302 | } 303 | 304 | void token_push_backquote_lit(Vector *self, char *str, uint8_t len, SrcPos s, SrcPos e) { 305 | enum tkind a = 0; 306 | 307 | if(len == 1) { 308 | a = op_char1(str[0]); 309 | } 310 | else if(len == 2) { 311 | a = op_char2(str[0], str[1]); 312 | } 313 | 314 | Token *tk = newtoken_bq(a, len, s, e); 315 | 316 | vec_push(self, tk); 317 | } 318 | 319 | void token_push_end(Vector *self, SrcPos s, SrcPos e) { 320 | Token *tk = newtoken_end(s, e); 321 | 322 | vec_push(self, tk); 323 | } 324 | 325 | static enum tkind ident2kw(char *k) { 326 | static int kwlen = sizeof(mxc_kwmap) / sizeof(mxc_kwmap[0]); 327 | 328 | for(int i = 0; i < kwlen; i++) { 329 | if(strcmp(k, mxc_kwmap[i].key) == 0) 330 | return mxc_kwmap[i].kind; 331 | } 332 | return TKIND_Identifer; 333 | } 334 | 335 | #ifdef MXC_DEBUG 336 | void tokendump(Vector *token) { 337 | for(int i = 0; i < token->len; ++i) { 338 | printf("kind: %s\t\t", tkind2str(((Token *)token->data[i])->kind)); 339 | printf("value: %s\t\t", ((Token *)token->data[i])->value); 340 | printf("len: %d\n", ((Token *)token->data[i])->len); 341 | } 342 | } 343 | #endif 344 | -------------------------------------------------------------------------------- /src/error/error.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "maxc.h" 7 | #include "error/error.h" 8 | 9 | extern char *filename; 10 | extern char *code; 11 | int errcnt = 0; 12 | 13 | void errheader(SrcPos start, SrcPos end) { 14 | fprintf(stderr, 15 | "\e[31;1m[error]\e[0m\e[1m(line %d:col %d): ", 16 | start.line, 17 | end.col); 18 | } 19 | 20 | void putsline(int lineno) { 21 | if(lineno < 0) { 22 | return; 23 | } 24 | log_error("\e[36;1m%d | \e[0m", lineno); 25 | 26 | int curline = 1; 27 | for(size_t i = 0; i < strlen(code); i++) { 28 | if(curline == lineno) { 29 | char *cur = code + i; 30 | int len = 0; 31 | while(code[i++] != '\n') 32 | len++; 33 | 34 | log_error("%.*s", len, cur); 35 | break; 36 | } 37 | 38 | if(code[i] == '\n') 39 | ++curline; 40 | } 41 | 42 | log_error("\n"); 43 | } 44 | 45 | void error(const char *msg, ...) { 46 | va_list args; 47 | va_start(args, msg); 48 | log_error("\e[31;1m[error] \e[0m\e[1m"); 49 | vfprintf(stderr, msg, args); 50 | log_error("\e[0m\n"); 51 | if(filename) 52 | log_error("\e[33;1min %s\e[0m\n", filename); 53 | va_end(args); 54 | } 55 | 56 | void errline(int line, char *msg, ...) { 57 | log_error("\e[31;1m[error]\e[0m\e[1m"); 58 | log_error("(line %d): ", line); 59 | log_error("\e[0m"); 60 | 61 | va_list args; 62 | va_start(args, msg); 63 | log_error("\e[1m"); 64 | vfprintf(stderr, msg, args); 65 | va_end(args); 66 | log_error("\e[0m"); 67 | log_error(STR_DEFAULT "\n\n"); 68 | 69 | putsline(line); 70 | 71 | log_error("\n"); 72 | } 73 | 74 | void error_nofile(const char *msg, ...) { 75 | va_list args; 76 | va_start(args, msg); 77 | log_error("\e[31;1m[error] \e[0m"); 78 | log_error("\e[1m"); 79 | vfprintf(stderr, msg, args); 80 | log_error("\e[0m\n"); 81 | va_end(args); 82 | } 83 | 84 | void warn(const char *msg, ...) { 85 | va_list args; 86 | va_start(args, msg); 87 | log_error("\e[94;1m[warning] \e[0m"); 88 | vfprintf(stderr, msg, args); 89 | log_error("\e[0m"); 90 | if(filename) 91 | log_error("\e[33;1min %s\e[0m ", filename); 92 | log_error("\n"); 93 | va_end(args); 94 | } 95 | 96 | void error_at(const SrcPos start, const SrcPos end, const char *msg, ...) { 97 | errheader(start, end); 98 | 99 | va_list args; 100 | va_start(args, msg); 101 | vfprintf(stderr, msg, args); 102 | log_error(STR_DEFAULT "\n"); 103 | 104 | int lline = end.line - start.line + 1; 105 | int lcol = end.col - start.col + 1; 106 | 107 | if(start.filename) { 108 | log_error("\e[33;1min %s\e[0m ", start.filename); 109 | log_error("\n\n"); 110 | } 111 | 112 | putsline(start.line); 113 | 114 | log_error("%*s", start.col + get_digit(start.line) + 2, " "); 115 | log_error("\e[31;1m"); 116 | log_error("%*s", lcol, "^"); 117 | log_error(STR_DEFAULT); 118 | log_error("\n\n"); 119 | va_end(args); 120 | } 121 | 122 | void mxc_unimplemented(const char *msg, ...) { 123 | va_list args; 124 | va_start(args, msg); 125 | log_error("\e[31;1m[unimplemented] \e[0m"); 126 | if(filename) 127 | log_error("\e[1m%s:\e[0m ", filename); 128 | vfprintf(stderr, msg, args); 129 | log_error("\n"); 130 | va_end(args); 131 | 132 | // our_interp()->errcnt++; 133 | } 134 | 135 | void unreachable_core(char *file, int line) { 136 | log_error("unreachable at %s:%d\n", file, line); 137 | exit(1); 138 | } 139 | 140 | void warning(const SrcPos start, const SrcPos end, const char *msg, ...) { 141 | va_list args; 142 | va_start(args, msg); 143 | log_error("\e[34;1m[warning]\e[0m\e[1m(line %d:col %d): ", 144 | start.line, 145 | start.col); 146 | vfprintf(stderr, msg, args); 147 | log_error(STR_DEFAULT); 148 | if(filename) { 149 | log_error("\e[33;1min %s\e[0m ", start.filename); 150 | log_error("\n\n"); 151 | } 152 | va_end(args); 153 | } 154 | 155 | void debug(const char *msg, ...) { 156 | va_list args; 157 | va_start(args, msg); 158 | log_error("\e[33;1m[debug] \e[0m"); 159 | vfprintf(stderr, msg, args); 160 | va_end(args); 161 | } 162 | 163 | void mxc_assert_core(int boolean, char *message, char *file, int line) { 164 | if(boolean == false) { 165 | log_error("\e[31;1m[assertion failed]: \e[0m"); 166 | log_error("\e[1m%s (%s:%d)\n\e[0m", message, file, line); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/maxc/internal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "maxc.h" 8 | 9 | ReadStatus intern_readline(size_t alloc, 10 | size_t *cursor, 11 | char *end, 12 | size_t end_len) { 13 | ReadStatus status = { 14 | .err.eof = 0, 15 | .err.toolong = 0 16 | }; 17 | char a[alloc]; 18 | memset(a, 0, alloc); 19 | char last_char; 20 | char *str; 21 | size_t max = alloc - end_len - 1; 22 | *cursor = 0; 23 | 24 | while((last_char = getchar()) != '\n') { 25 | if(last_char == EOF) { 26 | status.err.eof = 1; 27 | goto err; 28 | } 29 | 30 | a[(*cursor)++] = last_char; 31 | 32 | if(max <= *cursor) { 33 | status.err.toolong = 1; 34 | goto err; 35 | } 36 | } 37 | 38 | str = malloc(sizeof(char) * (*cursor + end_len + 1)); 39 | sprintf(str, "%s%s", a, end); 40 | 41 | status.str = str; 42 | return status; 43 | 44 | err: 45 | status.str = NULL; 46 | return status; 47 | } 48 | 49 | const unsigned int intern_ascii_to_numtable[] = { 50 | /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 51 | /*0*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 52 | /*1*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 53 | /*2*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 54 | /*3*/ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,99,99,99,99,99,99, 55 | /*4*/ 99,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 56 | /*5*/ 25,26,27,28,29,30,31,32,33,34,35,99,99,99,99,99, 57 | /*6*/ 99,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 58 | /*7*/ 25,26,27,28,29,30,31,32,33,34,35,99,99,99,99,99, 59 | /*8*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 60 | /*9*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 61 | /*a*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 62 | /*b*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 63 | /*c*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 64 | /*d*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 65 | /*e*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 66 | /*f*/ 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, 67 | }; 68 | 69 | int64_t intern_scan_digiti(char *str, int base, int *overflow, size_t *len) { 70 | char *s = str; 71 | int64_t res = 0; 72 | int64_t tmp; 73 | int d; 74 | int64_t mulov_border = INT64_MAX / base; 75 | 76 | while(*s) { 77 | d = intern_ascii_to_numtable[(int)*s++]; 78 | if(d >= base) { 79 | --s; 80 | // TODO: raise error 81 | break; 82 | } 83 | if(res > mulov_border) { 84 | *overflow = 1; 85 | --s; 86 | break; 87 | } 88 | res *= base; 89 | tmp = res; 90 | res += d; 91 | if(res < tmp) { 92 | *overflow = 1; 93 | --s; 94 | res = tmp / base; 95 | break; 96 | } 97 | } 98 | *len = s - str; 99 | 100 | return res; 101 | } 102 | 103 | int32_t intern_scan_digiti32(char *str, int base, int *overflow, size_t *len) { 104 | char *s = str; 105 | int32_t res = 0; 106 | int32_t tmp; 107 | int d; 108 | int32_t mulov_border = INT32_MAX / base; 109 | 110 | while(*s) { 111 | d = intern_ascii_to_numtable[(int)*s++]; 112 | if(d >= base) { 113 | --s; 114 | // TODO: raise error 115 | break; 116 | } 117 | if(res > mulov_border) { 118 | *overflow = 1; 119 | --s; 120 | break; 121 | } 122 | res *= base; 123 | tmp = res; 124 | res += d; 125 | if(res < tmp) { 126 | *overflow = 1; 127 | --s; 128 | res = tmp / base; 129 | break; 130 | } 131 | } 132 | *len = s - str; 133 | 134 | return res; 135 | } 136 | 137 | void *xmalloc(size_t n) { 138 | void *p = malloc(n); 139 | if(!p) 140 | panic("no memory"); 141 | return p; 142 | } 143 | 144 | void panic(char *msg, ...) { 145 | va_list args; 146 | va_start(args, msg); 147 | 148 | fprintf(stderr, "[panic]: "); 149 | vfprintf(stderr, msg, args); 150 | fprintf(stderr, "\n"); 151 | 152 | va_end(args); 153 | abort(); 154 | } 155 | -------------------------------------------------------------------------------- /src/maxc/main.c: -------------------------------------------------------------------------------- 1 | #include "maxc.h" 2 | 3 | int main(int argc, char **argv) { 4 | mxc_open(argc, argv); 5 | 6 | if(argc == 1) { 7 | return mxc_main_repl(); 8 | } 9 | 10 | int err = mxc_main_file(argv[1]); 11 | 12 | mxc_close(); 13 | 14 | return err; 15 | } 16 | -------------------------------------------------------------------------------- /src/maxc/maxc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "maxc.h" 4 | #include "ast.h" 5 | #include "bytecode.h" 6 | #include "codegen.h" 7 | #include "error/error.h" 8 | #include "lexer.h" 9 | #include "parser.h" 10 | #include "sema.h" 11 | #include "token.h" 12 | #include "type.h" 13 | #include "vm.h" 14 | #include "object/object.h" 15 | #include "literalpool.h" 16 | #include "mlib.h" 17 | 18 | const char *code; 19 | const char *filename; 20 | 21 | void mxc_open(int argc, char **argv) { 22 | setup_argv(argc, argv); 23 | module_init(); 24 | sema_init(); 25 | op_addr_table_init(); 26 | } 27 | 28 | void mxc_close() { 29 | ; 30 | } 31 | 32 | int mxc_main_file(const char *fname) { 33 | char *src = read_file(fname); 34 | if(!src) { 35 | error("%s: cannot open file", fname); 36 | return 1; 37 | } 38 | filename = fname; 39 | code = src; 40 | 41 | Vector *token = lexer_run(src, fname); 42 | 43 | #ifdef MXC_DEBUG 44 | tokendump(token); 45 | //printf(BOLD("--- lex: %s ---\n"), interp->errcnt ? "failed" : "success"); 46 | #endif 47 | 48 | struct mparser *pstate = parser_run(token); 49 | if(pstate->err) { 50 | return 1; 51 | } 52 | 53 | Vector *ast = pstate->ast; 54 | 55 | #ifdef MXC_DEBUG 56 | //printf(BOLD("--- parse: %s ---\n"), interp->errcnt ? "failed" : "success"); 57 | #endif 58 | 59 | Scope *s = sema_analysis(ast); 60 | if(s->err) { 61 | return 1; 62 | } 63 | 64 | #ifdef MXC_DEBUG 65 | //printf(BOLD("--- sema_analysis: %s ---\n"), interp->errcnt ? "failed" : "success"); 66 | #endif 67 | 68 | struct cgen *cinfo = compile(ast, s->ngvar); 69 | 70 | #ifdef MXC_DEBUG 71 | // printf(BOLD("--- compile: %s ---\n"), interp->errcnt ? "failed" : "success"); 72 | #endif 73 | 74 | #ifdef MXC_DEBUG 75 | puts(BOLD("--- literal pool ---")); 76 | lpooldump(cinfo->ltable); 77 | 78 | puts(BOLD("--- codedump ---")); 79 | printf("iseq len: %d\n", cinfo->iseq->len); 80 | 81 | /* 82 | printf("\e[2m"); 83 | for(size_t i = 0; i < cinfo->iseq->len;) { 84 | codedump(cinfo->iseq->code, &i, cinfo->ltable); 85 | puts(""); 86 | } 87 | puts(STR_DEFAULT); 88 | */ 89 | 90 | puts(BOLD("--- exec result ---")); 91 | #endif 92 | 93 | vm_open(cinfo->iseq->code, cinfo->gvars, s->ngvar, cinfo->ltable, cinfo->d); 94 | int exitcode = vm_run(); 95 | 96 | return exitcode; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /src/mlib/api.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mlibapi.h" 4 | #include "util.h" 5 | #include "internal.h" 6 | #include "object/mfunc.h" 7 | 8 | Vector *gmodule; 9 | 10 | static MCimpl *make_cimpl(NodeVariable *, MxcValue); 11 | 12 | static void cbltin_add_obj(Vector *c, NodeVariable *v, MxcValue i) { 13 | mgc_guard(i); 14 | vec_push(c, make_cimpl(v, i)); 15 | } 16 | 17 | MxcModule *new_mxcmodule(char *name) { 18 | MxcModule *m = malloc(sizeof(MxcModule)); 19 | m->name = name; 20 | m->cimpl = new_vector(); 21 | m->cmeth = new_vector(); 22 | m->ctypes = new_vector(); 23 | return m; 24 | } 25 | 26 | void define_cmeth(MxcModule *mod, char *name, cfunction impl, Type *ret, ...) { 27 | NodeVariable *var; 28 | Type *fntype; 29 | Vector *args = new_vector(); 30 | va_list argva; 31 | va_start(argva, ret); 32 | 33 | for(Type *t = va_arg(argva, Type *); t; t = va_arg(argva, Type *)) { 34 | vec_push(args, t); 35 | } 36 | 37 | fntype = new_type_function(args, ret); 38 | var = node_variable_type(name, 0, fntype, -1); 39 | 40 | MxcValue func = new_cfunc(impl); 41 | cbltin_add_obj(mod->cmeth, var, func); 42 | } 43 | 44 | void define_cfunc(MxcModule *mod, char *name, cfunction impl, Type *ret, ...) { 45 | NodeVariable *var; 46 | Type *fntype; 47 | Vector *args = new_vector(); 48 | va_list argva; 49 | va_start(argva, ret); 50 | 51 | for(Type *t = va_arg(argva, Type *); t; t = va_arg(argva, Type *)) { 52 | vec_push(args, t); 53 | } 54 | 55 | fntype = new_type_function(args, ret); 56 | var = node_variable_type(name, 0, fntype, -1); 57 | 58 | MxcValue func = new_cfunc(impl); 59 | cbltin_add_obj(mod->cimpl, var, func); 60 | } 61 | 62 | void define_cconst(MxcModule *mod, char *name, MxcValue val, Type *ty) { 63 | NodeVariable *var = node_variable_type(name, 0, ty, -1); 64 | cbltin_add_obj(mod->cimpl, var, val); 65 | } 66 | 67 | static MCimpl *make_cimpl(NodeVariable *v, MxcValue i) { 68 | MCimpl *cimpl = xmalloc(sizeof(MCimpl)); 69 | cimpl->var = v; 70 | cimpl->impl = i; 71 | 72 | return cimpl; 73 | } 74 | 75 | void define_ctype(MxcModule *mod, Type *type) { 76 | vec_push(mod->ctypes, type); 77 | } 78 | 79 | int mlib_parse_arg(MxcValue *arg, int narg, ...) { 80 | va_list ap; 81 | va_start(ap, narg); 82 | for(int i = 0; i < narg; i++) { 83 | MxcValue *v = va_arg(ap, MxcValue *); 84 | *v = arg[i]; 85 | } 86 | } 87 | 88 | void reg_gmodule(MxcModule *m) { 89 | vec_push(gmodule, m); 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/mlib/init.c: -------------------------------------------------------------------------------- 1 | #include "maxc.h" 2 | #include "mlib.h" 3 | #include "util.h" 4 | 5 | extern Vector *gmodule; 6 | 7 | void module_init() { 8 | gmodule = new_vector(); 9 | 10 | std_init(); 11 | file_init(); 12 | str_init(); 13 | list_init(); 14 | dir_init(); 15 | int_init(); 16 | } 17 | -------------------------------------------------------------------------------- /src/object/attr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "object/object.h" 3 | #include "object/attr.h" 4 | #include "object/system.h" 5 | 6 | MxcValue mxc_objattrget(MxcObject *ob, char *name) { 7 | struct mobj_attr *attr = SYSTEM(ob)->attr; 8 | for(struct mobj_attr a = *attr; a.attrname; a = *++attr) { 9 | if(!strcmp(a.attrname, name)) { 10 | return *(MxcValue *)(ob + a.offset); 11 | } 12 | } 13 | /* raise error */ 14 | } 15 | void mxc_objattrset(MxcObject *ob, char *name, MxcValue src) { 16 | struct mobj_attr *attr = SYSTEM(ob)->attr; 17 | for(struct mobj_attr a = *attr; a.attrname; a = *++attr) { 18 | if(!strcmp(a.attrname, name)) { 19 | *(MxcValue *)(ob + a.offset) = src; 20 | } 21 | } 22 | } 23 | 24 | struct mobj_attr mxc_objattr(struct mobj_attr *attr, char *name) { 25 | for(struct mobj_attr a = *attr; a.attrname; a = *++attr) { 26 | if(!strcmp(a.attrname, name)) { 27 | return a; 28 | } 29 | } 30 | return (struct mobj_attr){NULL}; 31 | } 32 | -------------------------------------------------------------------------------- /src/object/boolean.c: -------------------------------------------------------------------------------- 1 | /* implementation of boolean object */ 2 | 3 | #include "object/mbool.h" 4 | #include "error/error.h" 5 | #include "mem.h" 6 | #include "vm.h" 7 | -------------------------------------------------------------------------------- /src/object/dir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "object/object.h" 7 | #include "object/mdir.h" 8 | #include "object/system.h" 9 | #include "error/error.h" 10 | #include "mem.h" 11 | #include "mlib.h" 12 | 13 | static MxcValue newdir(MString *path) { 14 | NEW_OBJECT(MDir, md, dir_sys); 15 | 16 | DIR *dir = opendir(path->str); 17 | if(!dir) { 18 | /* raise error */ 19 | return mval_null; 20 | } 21 | 22 | md->dir = dir; 23 | md->path = path; 24 | 25 | return mval_obj(md); 26 | } 27 | 28 | MxcValue m_opendir(MxcValue *args, size_t nargs) { 29 | return newdir(ostr(args[0])); 30 | } 31 | 32 | static MxcValue dir_read(MDir *dir) { 33 | ; 34 | } 35 | 36 | static MxcValue dir_children(MDir *dir) { 37 | struct dirent *de; 38 | MList *l = (MList *)V2O(new_list(4)); 39 | OBJGCGUARD(dir); 40 | OBJGCGUARD(l); 41 | 42 | while((de = readdir(dir->dir))) { 43 | char *fname = de->d_name; 44 | if(!strcmp(fname, ".") || !strcmp(fname, "..")) { 45 | continue; 46 | } 47 | 48 | listadd(l, new_string_static(fname, strlen(fname))); 49 | } 50 | 51 | OBJGCUNGUARD(dir); 52 | OBJGCUNGUARD(l); 53 | 54 | return mval_obj(l); 55 | } 56 | 57 | static MxcValue mdir_children(MxcValue *args, size_t nargs) { 58 | return dir_children((MDir *)V2O(args[0])); 59 | } 60 | 61 | static void d_gc_mark(MxcObject *ob) { 62 | if(OBJGCMARKED(ob)) return; 63 | OBJGCMARK(ob); 64 | MDir *d = (MDir *)ob; 65 | SYSTEM(d->path)->mark((MxcObject *)d->path); 66 | } 67 | 68 | static void d_guard(MxcObject *ob) { 69 | OBJGCGUARD(ob); 70 | MDir *d = (MDir *)ob; 71 | SYSTEM(d->path)->guard((MxcObject *)d->path); 72 | } 73 | 74 | static void d_unguard(MxcObject *ob) { 75 | OBJGCUNGUARD(ob); 76 | MDir *d = (MDir *)ob; 77 | SYSTEM(d->path)->unguard((MxcObject *)d->path); 78 | } 79 | 80 | void d_dealloc(MxcObject *s) { 81 | MDir *d = (MDir *)s; 82 | closedir(d->dir); 83 | Mxc_free(d->path); 84 | Mxc_free(d); 85 | } 86 | 87 | MxcValue d_tostring(MxcObject *ob) { 88 | MDir *d = (MDir *)ob; 89 | GC_GUARD(d); 90 | char buf[1024] = {0}; /* ? */ 91 | sprintf(buf, "", d->path->str); 92 | 93 | MxcValue s = new_string(buf, strlen(buf)); 94 | 95 | GC_UNGUARD(d); 96 | 97 | return s; 98 | } 99 | 100 | struct mobj_system dir_sys = { 101 | "Dir", 102 | NULL, 103 | d_tostring, 104 | d_dealloc, 105 | 0, 106 | d_gc_mark, 107 | d_guard, 108 | d_unguard, 109 | 0, 110 | 0, 111 | 0, 112 | 0, 113 | 0, 114 | obj_hash32, 115 | 0, 116 | }; 117 | 118 | void dir_init() { 119 | MxcModule *mod = new_mxcmodule("Dir"); 120 | 121 | Type *dir_t = userdef_type("Dir", T_SHOWABLE); 122 | 123 | define_cfunc(mod, "opendir", m_opendir, FTYPE(dir_t, mxc_string)); 124 | define_cfunc(mod, "children", mdir_children, FTYPE(new_type_list(mxc_string), dir_t)); 125 | 126 | define_ctype(mod, dir_t); 127 | 128 | reg_gmodule(mod); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /src/object/encoding.c: -------------------------------------------------------------------------------- 1 | #include "object/encoding.h" 2 | -------------------------------------------------------------------------------- /src/object/exception.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "object/mexception.h" 7 | #include "vm.h" 8 | #include "error.h" 9 | 10 | extern mptr_t **pcsaver; 11 | 12 | NEW_EXCEPTION(exc_outofrange, "out_of_range"); 13 | NEW_EXCEPTION(exc_zero_division, "zero_division"); 14 | NEW_EXCEPTION(exc_assert, "assertion"); 15 | NEW_EXCEPTION(exc_file, "file"); 16 | NEW_EXCEPTION(exc_eof, "EOF"); 17 | NEW_EXCEPTION(exc_notfound, "not_found"); 18 | 19 | void mxc_raise(MException *e, char *msg, ...) { 20 | char buf[1024] = {0}; 21 | int msg_size; 22 | MContext *c = curvm()->ctx; 23 | va_list arg; 24 | va_start(arg, msg); 25 | 26 | if((msg_size = vsnprintf(buf, sizeof(buf), msg, arg)) < 0) return; 27 | 28 | e->msg = (MString *)V2O(new_string_copy(buf, msg_size)); 29 | c->exc = e; 30 | 31 | if(!c->err_handling_enabled) 32 | exc_report(e); 33 | } 34 | 35 | void exc_report(MException *e) { 36 | MContext *c = curvm()->ctx; 37 | if(c->d) { 38 | int lineno = curlineno(c->d, *pcsaver, c->basepc); 39 | fprintf(stderr, "%s:%d [%s error] %s\n", 40 | c->d->filename, lineno, e->errname, e->msg? e->msg->str : ""); 41 | putsline(lineno); 42 | } 43 | else { 44 | fprintf(stderr, "[%s error] %s\n", e->errname, e->msg? e->msg->str : ""); 45 | } 46 | vm_force_exit(1); 47 | } 48 | -------------------------------------------------------------------------------- /src/object/fiber.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "object/mfiber.h" 5 | #include "object/system.h" 6 | #include "error/error.h" 7 | #include "internal.h" 8 | #include "function.h" 9 | #include "context.h" 10 | #include "mlibapi.h" 11 | #include "vm.h" 12 | #include "mem.h" 13 | 14 | MxcValue new_mfiber(userfunction *uf, MContext *c) { 15 | NEW_OBJECT(MFiber, fib, fiber_sys); 16 | 17 | fib->ctx = new_econtext(uf->code, uf->nlvars, uf->d, c); 18 | fib->state = CREATED; 19 | fib->ctx->fiber = fib; 20 | 21 | return mval_obj(fib); 22 | } 23 | 24 | MxcValue myield(MContext *c, MxcValue arg) { 25 | if(!c->fiber) { 26 | panic("NULL context"); 27 | } 28 | c->fiber->state = SUSPENDING; 29 | return arg; 30 | } 31 | 32 | MxcValue fiber_yield(MContext *c, MxcValue *args, size_t nargs) { 33 | if(!c->fiber) { 34 | panic("NULL context"); 35 | } 36 | c->fiber->state = SUSPENDING; 37 | return args[0]; 38 | } 39 | 40 | MxcValue mfiber_yield(MxcValue *args, size_t nargs) { 41 | MContext *c = curvm()->ctx; 42 | return fiber_yield(c, args, nargs); 43 | } 44 | 45 | MxcValue fiber_resume(MxcObject *f) { 46 | MFiber *fib = (MFiber *)f; 47 | VM *vm = curvm(); 48 | 49 | switch(fib->state) { 50 | case RUNNING: 51 | case DEAD: 52 | return mval_invalid; 53 | default: break; 54 | } 55 | 56 | fib->state = RUNNING; 57 | MContext *ctx = vm->ctx; 58 | vm->ctx = fib->ctx; 59 | 60 | int r = (int)(intptr_t)vm_exec(vm); 61 | 62 | vm->ctx = ctx; 63 | 64 | /* FIXME */ 65 | MxcValue result; 66 | switch(scstate) { 67 | case SCXX: result = POP(); break; 68 | case SCAX: result = screg_a; break; 69 | case SCBX: result = screg_b; break; 70 | case SCBA: result = screg_a; PUSH(screg_b); break; 71 | case SCAB: result = screg_b; PUSH(screg_a); break; 72 | } 73 | 74 | scstate = SCXX; 75 | 76 | if(r == 0) { /* r == 0: return, r == 1: yield */ 77 | fib->state = DEAD; 78 | return mval_invalid; 79 | } 80 | 81 | return result; 82 | } 83 | 84 | static MxcValue fiber_dead(MxcObject *f) { 85 | return ((MFiber *)f)->state == DEAD? mval_true : mval_false; 86 | } 87 | 88 | MxcValue fiber_tostring(MxcObject *ob) { 89 | MFiber *f = (MFiber *)ob; 90 | char buf[128] = {0}; 91 | static const char *map[] = { 92 | [CREATED] = "created", 93 | [RUNNING] = "running", 94 | [SUSPENDING] = "suspending", 95 | [DEAD] = "dead", 96 | }; 97 | 98 | sprintf(buf, "%s fiber@%p", map[f->state], f); 99 | char *s = malloc(strlen(buf) + 1); 100 | strcpy(s, buf); 101 | return new_string(s, strlen(buf)); 102 | } 103 | 104 | static void fiber_dealloc(MxcObject *ob) { 105 | MFiber *f = (MFiber *)ob; 106 | delete_context(f->ctx); 107 | Mxc_free(f); 108 | } 109 | 110 | static void fiber_gc_mark(MxcObject *ob) { 111 | OBJGCMARK(ob); 112 | MFiber *f = (MFiber *)ob; 113 | MContext *c = f->ctx; 114 | MxcValue v; 115 | while(c && c->fiber) { 116 | for(size_t i = 0; i < c->nlvars; i++) { 117 | v = c->lvars[i]; 118 | mgc_mark(v); 119 | } 120 | c = c->prev; 121 | } 122 | } 123 | 124 | static void fiber_gc_guard(MxcObject *ob) { 125 | OBJGCGUARD(ob); 126 | MFiber *f = (MFiber *)ob; 127 | MContext *c = f->ctx; 128 | MxcValue v; 129 | while(c && c->fiber) { 130 | for(size_t i = 0; i < c->nlvars; i++) { 131 | v = c->lvars[i]; 132 | mgc_guard(v); 133 | } 134 | c = c->prev; 135 | } 136 | } 137 | 138 | static void fiber_gc_unguard(MxcObject *ob) { 139 | OBJGCUNGUARD(ob); 140 | MFiber *f = (MFiber *)ob; 141 | MContext *c = f->ctx; 142 | MxcValue v; 143 | while(c && c->fiber) { 144 | for(size_t i = 0; i < c->nlvars; i++) { 145 | v = c->lvars[i]; 146 | mgc_unguard(v); 147 | } 148 | c = c->prev; 149 | } 150 | } 151 | 152 | static MxcValue fiber_get(MxcObject *f) { 153 | return mval_obj(f); 154 | } 155 | 156 | struct mobj_system fiber_sys = { 157 | "fiber", 158 | NULL, 159 | fiber_tostring, 160 | fiber_dealloc, 161 | 0, 162 | fiber_gc_mark, 163 | fiber_gc_guard, 164 | fiber_gc_unguard, 165 | 0, 166 | 0, 167 | fiber_get, 168 | fiber_resume, 169 | fiber_dead, 170 | obj_hash32, 171 | }; 172 | -------------------------------------------------------------------------------- /src/object/float.c: -------------------------------------------------------------------------------- 1 | /* implementation of float object */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "object/mfloat.h" 7 | #include "error/error.h" 8 | #include "mem.h" 9 | #include "vm.h" 10 | 11 | MxcValue float_copy(MxcValue v) { 12 | return v; 13 | } 14 | 15 | MxcValue float_eq(MxcValue l, MxcValue r) { 16 | if(V2F(l) == V2F(r)) 17 | return mval_true; 18 | else 19 | return mval_false; 20 | } 21 | 22 | MxcValue float_neq(MxcValue l, MxcValue r) { 23 | if(V2F(l) != V2F(r)) 24 | return mval_true; 25 | else 26 | return mval_false; 27 | } 28 | 29 | MxcValue float_lt(MxcValue l, MxcValue r) { 30 | if(V2F(l) < V2F(r)) 31 | return mval_true; 32 | else 33 | return mval_false; 34 | } 35 | 36 | MxcValue float_lte(MxcValue l, MxcValue r) { 37 | if(V2F(l) <= V2F(r)) 38 | return mval_true; 39 | else 40 | return mval_false; 41 | } 42 | 43 | MxcValue float_gt(MxcValue l, MxcValue r) { 44 | if(V2F(l) > V2F(r)) 45 | return mval_true; 46 | else 47 | return mval_false; 48 | } 49 | 50 | MxcValue float_div(MxcValue l, MxcValue r) { 51 | if(V2F(r) == 0.0) { 52 | return mval_invalid; 53 | } 54 | 55 | return mval_float(V2F(l) / V2F(r)); 56 | } 57 | 58 | MxcValue float_tostring(MxcValue val) { 59 | double f = V2F(val); 60 | size_t len = get_digit((int)f) + 10; 61 | char *str = malloc(sizeof(char) * len); 62 | sprintf(str, "%.8lf", f); 63 | 64 | return new_string(str, len); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/object/function.c: -------------------------------------------------------------------------------- 1 | /* implementation of function object */ 2 | #include 3 | #include 4 | #include "object/object.h" 5 | #include "object/system.h" 6 | #include "object/mfunc.h" 7 | #include "object/mfiber.h" 8 | #include "error/error.h" 9 | #include "mem.h" 10 | #include "gc.h" 11 | #include "vm.h" 12 | #include "execarg.h" 13 | 14 | int userfn_call(MCallable *self, MContext *c, size_t nargs) { 15 | INTERN_UNUSE(nargs); 16 | 17 | VM *vm = curvm(); 18 | MxcFunction *callee = (MxcFunction *)self; 19 | userfunction *f = callee->func; 20 | vm->ctx = new_econtext(f->code, f->nlvars, f->d, c); 21 | int res = (int)(intptr_t)vm_exec(vm); 22 | 23 | delete_context(vm->ctx); 24 | vm->ctx = c; 25 | return res; 26 | } 27 | 28 | MxcValue new_function(userfunction *u, bool iter) { 29 | NEW_OBJECT(MxcFunction, ob, userfn_sys); 30 | 31 | ob->func = u; 32 | ob->iter = iter; 33 | ((MCallable *)ob)->call = userfn_call; 34 | 35 | return mval_obj(ob); 36 | } 37 | 38 | MxcValue userfn_copy(MxcObject *u) { 39 | MxcFunction *n = (MxcFunction *)mxc_alloc(sizeof(MxcFunction)); 40 | memcpy(n, u, sizeof(MxcFunction)); 41 | 42 | return mval_obj(n); 43 | } 44 | 45 | static void userfn_mark(MxcObject *ob) { 46 | if(OBJGCMARKED(ob)) return; 47 | OBJGCMARK(ob); 48 | } 49 | 50 | static void userfn_guard(MxcObject *ob) { 51 | OBJGCGUARD(ob); 52 | } 53 | 54 | static void userfn_unguard(MxcObject *ob) { 55 | OBJGCUNGUARD(ob); 56 | } 57 | 58 | static void userfn_dealloc(MxcObject *ob) { 59 | free(((MxcFunction *)ob)->func); 60 | Mxc_free(ob); 61 | } 62 | 63 | int cfn_call(MCallable *self, MContext *context, size_t nargs) { 64 | extern enum stack_cache_state scstate; 65 | 66 | VM *vm = curvm(); 67 | MxcCFunc *callee = (MxcCFunc *)self; 68 | MxcValue *stack_argv = vm->stackptr - nargs; 69 | 70 | /* 71 | int ncache = SC_NCACHE(); 72 | int dec_sp = nargs - ncache; 73 | if(dec_sp < 0) { 74 | dec_sp = 0; 75 | } 76 | stack_argv -= dec_sp; 77 | 78 | if(ncache && dec_sp) 79 | memmove(stack_argv + ncache, stack_argv, dec_sp); 80 | 81 | MxcValue top; 82 | MxcValue second; 83 | if(ncache == 2) { 84 | if(SC_TOPA()) { 85 | top = screg_a; 86 | second = screg_b; 87 | } 88 | else { 89 | top = screg_b; 90 | second = screg_a; 91 | } 92 | 93 | if(nargs >= 2) { 94 | stack_argv[0] = top; 95 | stack_argv[1] = second; 96 | } 97 | else if(nargs == 1) { 98 | stack_argv[0] = top; 99 | } 100 | } 101 | else if(ncache == 1) { 102 | if(SC_TOPA()) { 103 | top = screg_a; 104 | } 105 | else { 106 | top = screg_b; 107 | } 108 | 109 | if(nargs >= 1) { 110 | stack_argv[0] = top; 111 | } 112 | } 113 | */ 114 | 115 | MxcValue ret = callee->func(stack_argv, nargs); 116 | vm->stackptr = stack_argv; 117 | screg_a = ret; 118 | scstate = SCAX; 119 | 120 | return 0; 121 | } 122 | 123 | MxcValue new_cfunc(cfunction cf) { 124 | NEW_OBJECT(MxcCFunc, ob, cfn_sys); 125 | 126 | ob->func = cf; 127 | ((MCallable *)ob)->call = cfn_call; 128 | 129 | return mval_obj(ob); 130 | } 131 | 132 | MxcValue cfn_copy(MxcObject *b) { 133 | MxcCFunc *n = (MxcCFunc *)mxc_alloc(sizeof(MxcCFunc)); 134 | memcpy(n, b, sizeof(MxcCFunc)); 135 | INCREF(b); 136 | 137 | return mval_obj(n); 138 | } 139 | 140 | static void cfn_dealloc(MxcObject *ob) { 141 | Mxc_free(ob); 142 | } 143 | 144 | static void cfn_mark(MxcObject *ob) { 145 | if(OBJGCMARKED(ob)) return; 146 | OBJGCMARK(ob); 147 | } 148 | 149 | static void cfn_guard(MxcObject *ob) { 150 | OBJGCGUARD(ob); 151 | } 152 | 153 | static void cfn_unguard(MxcObject *ob) { 154 | OBJGCUNGUARD(ob); 155 | } 156 | 157 | static MxcValue userfn_tostring(MxcObject *ob) { 158 | char *s = malloc(sizeof(char *) * 64); 159 | int len = sprintf(s, "", ob); 160 | 161 | return new_string(s, (size_t)len); 162 | } 163 | 164 | static MxcValue cfn_tostring(MxcObject *ob) { 165 | char *s = malloc(sizeof(char *) * 64); 166 | int len = sprintf(s, "", ob); 167 | 168 | return new_string(s, (size_t)len); 169 | } 170 | 171 | struct mobj_system userfn_sys = { 172 | "user-def function", 173 | NULL, 174 | userfn_tostring, 175 | userfn_dealloc, 176 | userfn_copy, 177 | userfn_mark, 178 | userfn_guard, 179 | userfn_unguard, 180 | 0, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | obj_hash32, 186 | }; 187 | 188 | struct mobj_system cfn_sys = { 189 | "builtin function", 190 | NULL, 191 | cfn_tostring, 192 | cfn_dealloc, 193 | cfn_copy, 194 | cfn_mark, 195 | cfn_guard, 196 | cfn_unguard, 197 | 0, 198 | 0, 199 | 0, 200 | 0, 201 | 0, 202 | obj_hash32, 203 | }; 204 | 205 | -------------------------------------------------------------------------------- /src/object/int.c: -------------------------------------------------------------------------------- 1 | /* implementation of integer object */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "object/mint.h" 8 | #include "error/error.h" 9 | #include "mem.h" 10 | #include "vm.h" 11 | 12 | void int_divrem(MxcValue l, MxcValue r, MxcValue *quo, MxcValue *rem) { 13 | int64_t x = V2I(l); 14 | int64_t y = V2I(r); 15 | if(y == 0) { 16 | mxc_raise(EXC_ZERO_DIVISION, "divide by 0"); 17 | if(quo) *quo = mval_invalid; 18 | if(rem) *rem = mval_invalid; 19 | return; 20 | } 21 | 22 | if(x == INT64_MIN && y == -1) { 23 | *quo = uint_to_integer((uint64_t)INT64_MAX + 1); 24 | *rem = mval_int(0); 25 | return; 26 | } 27 | int64_t qq = x / y; 28 | int64_t rr = x % y; 29 | 30 | if(quo) *quo = mval_int(qq); 31 | if(rem) *rem = mval_int(rr); 32 | } 33 | 34 | MxcValue int2str(MxcValue val, int base) { 35 | bool neg = false; 36 | char buf[sizeof(int32_t) * CHAR_BIT + 1] = {0}; 37 | char *end = buf + sizeof(buf); 38 | char *cur = end; 39 | int32_t num = V2I(val); 40 | uint32_t unum; 41 | 42 | if(base < 2 || 36 < base) { 43 | return mval_null; 44 | } 45 | 46 | if(num == 0) { 47 | return new_string_static("0", 1); 48 | } 49 | if(num < 0) { 50 | unum = (uint32_t)(-(num + 1)) + 1; 51 | neg = true; 52 | } 53 | else { 54 | unum = (uint32_t)num; 55 | } 56 | 57 | do { 58 | *--cur = mxc_36digits[unum % base]; 59 | } while(unum /= base); 60 | if(neg) { 61 | *--cur = '-'; 62 | } 63 | 64 | return new_string_copy(cur, end - cur); 65 | } 66 | 67 | MxcValue int_tostring(MxcValue val) { 68 | return int2str(val, 10); 69 | } 70 | -------------------------------------------------------------------------------- /src/object/iter.c: -------------------------------------------------------------------------------- 1 | /* implementation of iterator object */ 2 | #include "object/miter.h" 3 | #include "object/system.h" 4 | #include "error/error.h" 5 | #include "mem.h" 6 | #include "vm.h" 7 | 8 | MxcValue iterable_reset(MxcIterable *iter) { 9 | iter->index = 0; 10 | return mval_obj(iter); 11 | } 12 | 13 | MxcValue iterable_stopped(MxcIterable *iter) { 14 | return iter->index == iter->length? mval_true : mval_false; 15 | } 16 | 17 | MxcValue iterable_next(MxcIterable *iter) { 18 | if(iter->length <= iter->index) 19 | return mval_invalid; 20 | 21 | MxcValue res = SYSTEM(iter)->get(iter, mval_int(iter->index)); 22 | iter->index++; 23 | return res; 24 | } 25 | -------------------------------------------------------------------------------- /src/object/list.c: -------------------------------------------------------------------------------- 1 | /* implementation of list object */ 2 | #include 3 | #include 4 | #include 5 | #include "object/mlist.h" 6 | #include "object/system.h" 7 | #include "object/mexception.h" 8 | #include "type.h" 9 | #include "error/error.h" 10 | #include "mlib.h" 11 | #include "mem.h" 12 | #include "vm.h" 13 | 14 | MxcValue new_list(size_t size) { 15 | NEW_OBJECT(MList, ob, list_sys); 16 | 17 | size = size? size : 1; 18 | 19 | ob->elem = malloc(sizeof(MxcValue) * size); 20 | LISTCAPA(ob) = size; 21 | LISTLEN(ob) = 0; 22 | 23 | return mval_obj(ob); 24 | } 25 | 26 | MxcValue list_copy(MxcObject *l) { 27 | MList *ob = (MList *)mxc_alloc(sizeof(MList)); 28 | memcpy(ob, l, sizeof(MList)); 29 | 30 | MxcValue *old = ob->elem; 31 | ob->elem = malloc(sizeof(MxcValue) * LISTLEN(ob)); 32 | for(size_t i = 0; i < LISTLEN(ob); ++i) { 33 | ob->elem[i] = mval_copy(old[i]); 34 | } 35 | 36 | return mval_obj(ob); 37 | } 38 | 39 | MxcValue new_list2(MxcValue *es, size_t nes) { 40 | NEW_OBJECT(MList, ob, list_sys); 41 | 42 | ob->elem = malloc(sizeof(MxcValue) * nes); 43 | memcpy(ob->elem, es, sizeof(MxcValue) * nes); 44 | LISTCAPA(ob) = nes? nes : 1; 45 | LISTLEN(ob) = nes; 46 | 47 | return mval_obj(ob); 48 | } 49 | 50 | MxcValue new_list_size(MxcValue size, MxcValue init) { 51 | NEW_OBJECT(MList, ob, list_sys); 52 | 53 | int32_t len = V2I(size); 54 | ITERABLE(ob)->length = len; 55 | 56 | if(len < 0) { 57 | mxc_raise(EXC_OUTOFRANGE, "negative length"); 58 | return mval_invalid; 59 | } 60 | 61 | ob->elem = malloc(sizeof(MxcValue) * len); 62 | MxcValue *ptr = ob->elem; 63 | while(len--) { 64 | *ptr++ = init; 65 | } 66 | 67 | return mval_obj(ob); 68 | } 69 | 70 | MxcValue mlistget(MList *l, MxcValue idx) { 71 | int32_t i = V2I(idx); 72 | if(i < 0) { 73 | i = LISTLEN(l) + i; 74 | } 75 | 76 | if(LISTLEN(l) <= i) { 77 | mxc_raise(EXC_OUTOFRANGE, "out of range"); 78 | return mval_invalid; 79 | } 80 | 81 | return l->elem[i]; 82 | } 83 | 84 | MxcValue mlistset(MList *l, MxcValue idx, MxcValue a) { 85 | int32_t i = V2I(idx); 86 | if(i < 0) { 87 | i = LISTLEN(l) + i; 88 | } 89 | 90 | if(LISTLEN(l) <= i) { 91 | mxc_raise(EXC_OUTOFRANGE, "out of range"); 92 | return mval_invalid; 93 | } 94 | l->elem[i] = a; 95 | 96 | return a; 97 | } 98 | 99 | static MxcValue list_get(MxcIterable *self, MxcValue idx) { 100 | MList *list = (MList *)self; 101 | 102 | return mlistget(list, idx); 103 | } 104 | 105 | static MxcValue list_set(MxcIterable *self, MxcValue idx, MxcValue a) { 106 | MList *list = (MList *)self; 107 | 108 | return mlistset(list, idx, a); 109 | } 110 | 111 | MxcValue listlen(MList *l) { 112 | return mval_int(LISTLEN(l)); 113 | } 114 | 115 | MxcValue mlistlen(MxcValue *a, size_t na) { 116 | return listlen((MList *)V2O(a[0])); 117 | } 118 | 119 | MxcValue listclear(MList *l) { 120 | LISTLEN(l) = 0; 121 | return mval_null; 122 | } 123 | 124 | static MxcValue mlistclear(MxcValue *a, size_t na) { 125 | return listclear((MList *)V2O(a[0])); 126 | } 127 | 128 | static void listexpand(MList *l) { 129 | LISTCAPA(l) *= 2; 130 | l->elem = realloc(l->elem, sizeof(MxcValue) * LISTCAPA(l)); 131 | } 132 | 133 | MxcValue listadd(MList *l, MxcValue a) { 134 | if(LISTLEN(l) == LISTCAPA(l)) { 135 | listexpand(l); 136 | } 137 | 138 | l->elem[LISTLEN(l)] = a; 139 | LISTLEN(l) += 1; 140 | return mval_obj(l); 141 | } 142 | 143 | MxcValue mlistadd(MxcValue *a, size_t na) { 144 | return listadd((MList *)V2O(a[0]), a[1]); 145 | } 146 | 147 | MxcValue listdel_at(MList *l, int64_t idx) { 148 | MxcValue *e = l->elem; 149 | for(int i = idx; i < LISTLEN(l) - 1; i++) { 150 | e[i] = e[i + 1]; 151 | } 152 | 153 | LISTLEN(l) -= 1; 154 | 155 | return mval_null; 156 | } 157 | 158 | static MxcValue mlistdel_at(MxcValue *a, size_t na) { 159 | return listdel_at((MList *)V2O(a[0]), V2I(a[1])); 160 | } 161 | 162 | MxcValue listpop(MList *l) { 163 | MxcValue val = l->elem[LISTLEN(l) - 1]; 164 | LISTLEN(l) -= 1; 165 | return val; 166 | } 167 | 168 | static MxcValue mlistpop(MxcValue *a, size_t na) { 169 | return listpop((MList *)V2O(a[0])); 170 | } 171 | 172 | MxcValue listrev(MList *l) { 173 | MxcValue *elem = l->elem; 174 | int end = LISTLEN(l) - 1; 175 | 176 | for(int i = 0; i < end; i++, end--) { 177 | MxcValue tmp = elem[i]; 178 | elem[i] = elem[end]; 179 | elem[end] = tmp; 180 | } 181 | 182 | return mval_obj(l); 183 | } 184 | 185 | MxcValue mlistrev(MxcValue *a, size_t na) { 186 | return listrev((MList *)V2O(a[0])); 187 | } 188 | 189 | static MxcValue listreversed(MList *l) { 190 | MxcValue newl = new_list(LISTLEN(l)); 191 | MList *n = (MList *)V2O(newl); 192 | 193 | for(int i = LISTLEN(l) - 1; i >= 0; i--) { 194 | listadd(n, l->elem[i]); 195 | } 196 | 197 | return mval_obj(n); 198 | } 199 | 200 | MxcValue mlistreversed(MxcValue *a, size_t na) { 201 | return listreversed((MList *)V2O(a[0])); 202 | } 203 | 204 | void list_dealloc(MxcObject *ob) { 205 | MList *l = (MList *)ob; 206 | 207 | Mxc_free(ob); 208 | } 209 | 210 | void list_gc_mark(MxcObject *ob) { 211 | if(OBJGCMARKED(ob)) return; 212 | MList *l = (MList *)ob; 213 | 214 | OBJGCMARK(ob); 215 | for(size_t i = 0; i < LISTLEN(l); ++i) { 216 | mgc_mark(l->elem[i]); 217 | } 218 | } 219 | 220 | void list_guard(MxcObject *ob) { 221 | MList *l = (MList *)ob; 222 | 223 | OBJGCGUARD(ob); 224 | for(size_t i = 0; i < LISTLEN(l); ++i) { 225 | mgc_guard(l->elem[i]); 226 | } 227 | } 228 | 229 | void list_unguard(MxcObject *ob) { 230 | MList *l = (MList *)ob; 231 | 232 | OBJGCUNGUARD(ob); 233 | for(size_t i = 0; i < LISTLEN(l); ++i) { 234 | mgc_unguard(l->elem[i]); 235 | } 236 | } 237 | 238 | MxcValue list_tostring(MxcObject *ob) { 239 | MxcValue res; 240 | MList *l = (MList *)ob; 241 | GC_GUARD(l); 242 | 243 | if(ITERABLE(l)->length == 0) { 244 | res = new_string_static("[]", 2); 245 | GC_UNGUARD(l); 246 | return res; 247 | } 248 | 249 | res = new_string_static("[", 1); 250 | mgc_guard(res); 251 | for(size_t i = 0; i < LISTLEN(l); ++i) { 252 | if(i > 0) 253 | str_cstr_append(ostr(res), ", ", 2); 254 | 255 | MxcValue elemstr = mval2str(l->elem[i]); 256 | str_append(ostr(res), ostr(elemstr)); 257 | } 258 | 259 | str_cstr_append(ostr(res), "]", 1); 260 | 261 | GC_UNGUARD(l); 262 | mgc_unguard(res); 263 | 264 | return res; 265 | } 266 | 267 | static uint32_t list_hash32(MxcObject *a) { 268 | MList *l = (MList *)a; 269 | size_t len = LISTLEN(l); 270 | 271 | uint32_t hash = 2166136261; 272 | 273 | for(size_t i = 0; i < len; i++) { 274 | uint32_t h = mval_hash32(l->elem[i]); 275 | hash = (hash ^ h) * 16777619; 276 | } 277 | 278 | return hash; 279 | } 280 | 281 | static bool internal_list_eq(MxcObject *_a, MxcObject *_b) { 282 | MList *a = (MList *)_a; 283 | MList *b = (MList *)_b; 284 | 285 | if(LISTLEN(a) != LISTLEN(b)) 286 | return false; 287 | 288 | for(int i = 0; i < LISTLEN(a); i++) { 289 | if(!mval_eq(a->elem[i], b->elem[i])) 290 | return false; 291 | } 292 | 293 | return true; 294 | } 295 | 296 | struct mobj_attr list_attr[] = { 297 | { "len", offsetof(MxcIterable, length), ATTR_READABLE, ATTY_CINT, mxc_int, 0 }, 298 | { NULL }, 299 | }; 300 | 301 | struct mobj_system list_sys = { 302 | "list", 303 | list_attr, 304 | list_tostring, 305 | list_dealloc, 306 | list_copy, 307 | list_gc_mark, 308 | list_guard, 309 | list_unguard, 310 | list_get, 311 | list_set, 312 | iterable_reset, 313 | iterable_next, 314 | iterable_stopped, 315 | list_hash32, 316 | internal_list_eq, 317 | }; 318 | 319 | void list_init() { 320 | MxcModule *mod = new_mxcmodule("list"); 321 | 322 | Type *vart = typevar("T"); 323 | Type *lvart = new_type_list(vart); 324 | define_cfunc(mod, "add", mlistadd, FTYPE(lvart, lvart, vart)); 325 | Type *vart2 = typevar("T"); 326 | Type *lvart2 = new_type_list(vart2); 327 | define_cfunc(mod, "reversed", mlistreversed, FTYPE(lvart2, lvart2)); 328 | Type *vart3 = typevar("T"); 329 | Type *lvart3 = new_type_list(vart3); 330 | define_cfunc(mod, "pop", mlistpop, FTYPE(vart3, lvart3)); 331 | Type *lvart4 = new_type_list(typevar("T")); 332 | define_cfunc(mod, "reverse", mlistrev, FTYPE(lvart4, lvart4)); 333 | Type *lvart5 = new_type_list(typevar("T")); 334 | define_cfunc(mod, "clear", mlistclear, FTYPE(mxc_none, lvart5)); 335 | Type *lvart6 = new_type_list(typevar("T")); 336 | define_cfunc(mod, "del_at", mlistdel_at, FTYPE(mxc_none, lvart6, mxc_int)); 337 | 338 | reg_gmodule(mod); 339 | } 340 | -------------------------------------------------------------------------------- /src/object/num.c: -------------------------------------------------------------------------------- 1 | #include "object/object.h" 2 | #include "object/num.h" 3 | #include "object/minteger.h" 4 | #include "object/mstr.h" 5 | #include "mlib.h" 6 | 7 | MxcValue num_add(MxcValue x, MxcValue y) { 8 | if(isint(x) && isint(y)) { 9 | return int_add(x, y); 10 | } 11 | x = isint(x) ? int_to_integer(V2I(x)) : x; 12 | y = isint(y) ? int_to_integer(V2I(y)) : y; 13 | 14 | return integer_add(x, y); 15 | } 16 | 17 | MxcValue num_sub(MxcValue x, MxcValue y) { 18 | if(isint(x) && isint(y)) { 19 | return int_sub(x, y); 20 | } 21 | x = isint(x) ? int_to_integer(V2I(x)) : x; 22 | y = isint(y) ? int_to_integer(V2I(y)) : y; 23 | 24 | return integer_sub(x, y); 25 | } 26 | 27 | MxcValue num_mul(MxcValue x, MxcValue y) { 28 | if(isint(x) && isint(y)) { 29 | return int_mul(x, y); 30 | } 31 | x = isint(x) ? int_to_integer(V2I(x)) : x; 32 | y = isint(y) ? int_to_integer(V2I(y)) : y; 33 | 34 | return integer_mul(x, y); 35 | } 36 | 37 | MxcValue num_div(MxcValue x, MxcValue y) { 38 | if(isint(x) && isint(y)) { 39 | return int_div(x, y); 40 | } 41 | x = isint(x) ? int_to_integer(V2I(x)) : x; 42 | y = isint(y) ? int_to_integer(V2I(y)) : y; 43 | 44 | return integer_divrem(x, y, NULL); 45 | } 46 | 47 | MxcValue num_mod(MxcValue x, MxcValue y) { 48 | if(isint(x) && isint(y)) { 49 | return int_rem(x, y); 50 | } 51 | x = isint(x) ? int_to_integer(V2I(x)) : x; 52 | y = isint(y) ? int_to_integer(V2I(y)) : y; 53 | 54 | MxcValue r; 55 | integer_divrem(x, y, &r); 56 | return r; 57 | } 58 | 59 | MxcValue num_eq(MxcValue x, MxcValue y) { 60 | if((isint(x) && isint(y)) || (isbool(x) && isbool(y))) { 61 | return int_eq(x, y); 62 | } 63 | x = isint(x) ? int_to_integer(V2I(x)) : x; 64 | y = isint(y) ? int_to_integer(V2I(y)) : y; 65 | 66 | return integer_eq(x, y); 67 | } 68 | 69 | MxcValue num_noteq(MxcValue x, MxcValue y) { 70 | if((isint(x) && isint(y)) || (isbool(x) && isbool(y))) { 71 | return int_noteq(x, y); 72 | } 73 | x = isint(x) ? int_to_integer(V2I(x)) : x; 74 | y = isint(y) ? int_to_integer(V2I(y)) : y; 75 | 76 | if(istrue(integer_eq(x, y))) 77 | return mval_false; 78 | else 79 | return mval_true; 80 | } 81 | 82 | MxcValue num_neg(MxcValue x) { 83 | if(isint(x)) { 84 | return mval_int(-V2I(x)); 85 | } 86 | 87 | MxcValue res = integer_copy(V2O(x)); 88 | obig(res)->sign = SIGN_MINUS; 89 | return res; 90 | } 91 | 92 | MxcValue num2str(MxcValue x, int base) { 93 | if(isint(x)) { 94 | return int2str(x, base); 95 | } 96 | else { 97 | return integer2str((MInteger *)V2O(x), base); 98 | } 99 | } 100 | 101 | static MxcValue m_num2str(MxcValue *args, size_t na) { 102 | return num2str(args[0], V2I(args[1])); 103 | } 104 | 105 | void int_init() { 106 | MxcModule *mod = new_mxcmodule("int"); 107 | 108 | define_cfunc(mod, "tostr", m_num2str, FTYPE(mxc_string, mxc_int, mxc_int)); 109 | 110 | reg_gmodule(mod); 111 | } 112 | -------------------------------------------------------------------------------- /src/object/object.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "object/object.h" 3 | #include "object/system.h" 4 | #include "error/error.h" 5 | #include "mem.h" 6 | #include "vm.h" 7 | 8 | const char mxc_36digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 9 | 10 | MxcValue mval2str(MxcValue val) { 11 | switch(mval_type(val)) { 12 | case VAL_OBJ: 13 | return SYSTEM(V2O(val))->tostring(V2O(val)); 14 | case VAL_INT: 15 | return int_tostring(val); 16 | case VAL_FLO: 17 | return float_tostring(val); 18 | case VAL_TRUE: 19 | return new_string_static("true", 4); 20 | case VAL_FALSE: 21 | return new_string_static("false", 5); 22 | case VAL_NULL: 23 | return new_string_static("null", 4); 24 | default: 25 | unreachable(); 26 | } 27 | 28 | return mval_invalid; 29 | } 30 | 31 | MxcValue mval_copy(MxcValue val) { 32 | switch(mval_type(val)) { 33 | case VAL_OBJ: return SYSTEM(V2O(val))->copy(V2O(val)); 34 | default: return val; 35 | } 36 | } 37 | 38 | bool mval_eq(MxcValue v1, MxcValue v2) { 39 | switch(mval_type(v1)) { 40 | case VAL_OBJ: return SYSTEM(V2O(v1))->eq(V2O(v1), V2O(v2)); 41 | case VAL_INT: return V2I(v1) == V2I(v2); 42 | case VAL_FLO: return V2F(v1) == V2F(v2); 43 | case VAL_TRUE: return mval_type(v2) == VAL_TRUE; 44 | case VAL_FALSE: return mval_type(v2) == VAL_FALSE; 45 | case VAL_NULL: return mval_type(v2) == VAL_NULL; 46 | default: unreachable(); 47 | } 48 | } 49 | 50 | void mgc_mark(MxcValue val) { 51 | switch(mval_type(val)) { 52 | case VAL_OBJ: SYSTEM(V2O(val))->mark(V2O(val)); break; 53 | default: break; 54 | } 55 | } 56 | 57 | void mgc_guard(MxcValue val) { 58 | switch(mval_type(val)) { 59 | case VAL_OBJ: SYSTEM(V2O(val))->guard(V2O(val)); break; 60 | default: break; 61 | } 62 | } 63 | 64 | void mgc_unguard(MxcValue val) { 65 | switch(mval_type(val)) { 66 | case VAL_OBJ: SYSTEM(V2O(val))->unguard(V2O(val)); break; 67 | default: break; 68 | } 69 | } 70 | 71 | uint32_t obj_hash32(MxcObject *ob) { 72 | return (uint32_t)(uint64_t)ob; 73 | } 74 | 75 | uint32_t mval_hash32(MxcValue key) { 76 | switch(mval_type(key)) { 77 | case VAL_OBJ: 78 | return SYSTEM(V2O(key))->hash(V2O(key)); 79 | default: 80 | return V2I(key); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/object/range.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "object/mrange.h" 4 | #include "object/system.h" 5 | #include "error/error.h" 6 | #include "mem.h" 7 | #include "mlib.h" 8 | 9 | extern struct mobj_system range_sys; 10 | 11 | static MxcValue new_range(MxcValue b, MxcValue e, int excl) { 12 | MRange *range = (MRange *)mxc_alloc(sizeof(MRange)); 13 | SYSTEM(range) = &range_sys; 14 | range->begin = b; 15 | range->end = e; 16 | range->excl = excl; 17 | 18 | return mval_obj(range); 19 | } 20 | 21 | struct mobj_system range_sys = { 22 | "range", 23 | 0, 24 | 0, 25 | 0, 26 | 0, 27 | 0, 28 | 0, 29 | 0, 30 | 0, 31 | 0, 32 | 0, 33 | }; 34 | -------------------------------------------------------------------------------- /src/object/std.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "maxc.h" 5 | #include "mlib.h" 6 | #include "mlibapi.h" 7 | #include "error/error.h" 8 | #include "object/object.h" 9 | #include "object/mint.h" 10 | #include "vm.h" 11 | #include "mem.h" 12 | #include "context.h" 13 | #include "gc.h" 14 | 15 | static MxcValue print(MxcValue *sp, size_t narg) { 16 | for(int i = 0; i < narg; i++) { 17 | MxcValue ob = sp[i]; 18 | MString *strob = ostr(mval2str(ob)); 19 | printf("%s", strob->str); 20 | } 21 | 22 | return mval_null; 23 | } 24 | 25 | static MxcValue println(MxcValue *sp, size_t narg) { 26 | MString *strob; 27 | if(narg == 0) { 28 | printf("\n"); 29 | return mval_null; 30 | } 31 | 32 | for(int i = 0; i < narg; i++) { 33 | MxcValue ob = sp[i]; 34 | strob = ostr(mval2str(ob)); 35 | printf("%s", strob->str); 36 | } 37 | 38 | if(strob->str[ITERABLE(strob)->length - 1] != '\n') 39 | printf("\n"); 40 | 41 | return mval_null; 42 | } 43 | 44 | static MxcValue mpanic(MxcValue *sp, size_t narg) { 45 | fprintf(stderr, "program panicked "); 46 | 47 | MString *strob; 48 | if(narg == 0) { 49 | fprintf(stderr, "\n"); 50 | exit(1); 51 | } 52 | 53 | for(int i = 0; i < narg; i++) { 54 | MxcValue ob = sp[i]; 55 | strob = ostr(mval2str(ob)); 56 | fprintf(stderr, "%s", strob->str); 57 | } 58 | 59 | if(strob->str[ITERABLE(strob)->length - 1] != '\n') 60 | fprintf(stderr, "\n"); 61 | 62 | exit(1); 63 | } 64 | 65 | static MxcValue int_tofloat(MxcValue *sp, size_t narg) { 66 | INTERN_UNUSE(narg); 67 | MxcValue val = sp[0]; 68 | double fnum = (double)V2I(val); 69 | 70 | return mval_float(fnum); 71 | } 72 | 73 | static MxcValue object_id(MxcValue *sp, size_t narg) { 74 | INTERN_UNUSE(narg); 75 | MxcValue ob = sp[0]; 76 | #ifdef NAN_BOXING 77 | intptr_t id = (intptr_t)ob.raw; 78 | #else 79 | intptr_t id = (intptr_t)V2O(ob); 80 | #endif 81 | 82 | return mval_int(id); 83 | } 84 | 85 | static MxcValue sys_exit(MxcValue *sp, size_t narg) __attribute__((noreturn)); 86 | 87 | static MxcValue sys_exit(MxcValue *sp, size_t narg) { 88 | INTERN_UNUSE(narg); 89 | MxcValue i = sp[0]; 90 | 91 | exit(V2I(i)); 92 | } 93 | 94 | static MxcValue mgc_run(MxcValue *sp, size_t narg) { 95 | INTERN_UNUSE(sp); 96 | INTERN_UNUSE(narg); 97 | 98 | gc_run(); 99 | 100 | return mval_null; 101 | } 102 | 103 | MxcValue margv; 104 | 105 | void setup_argv(int argc, char **argv) { 106 | margv = new_list(argc); 107 | for(int i = 0; i < argc; i++) { 108 | char *a_cstr = argv[i]; 109 | MxcValue a = new_string(a_cstr, strlen(a_cstr)); 110 | listadd((MList *)V2O(margv), a); 111 | } 112 | } 113 | 114 | void std_init() { 115 | MxcModule *mod = new_mxcmodule("std"); 116 | 117 | define_cfunc(mod, "print", print, mxc_none, mxc_any_vararg, NULL); 118 | define_cfunc(mod, "println", println, mxc_none, mxc_any_vararg, NULL); 119 | define_cfunc(mod, "echo", println, mxc_none, mxc_any_vararg, NULL); 120 | define_cfunc(mod, "panic", mpanic, mxc_none, mxc_any_vararg, NULL); 121 | define_cfunc(mod, "tofloat", int_tofloat, mxc_float, mxc_int, NULL); 122 | define_cfunc(mod, "objectid", object_id, mxc_int, mxc_any, NULL); 123 | define_cfunc(mod, "exit", sys_exit, mxc_none, mxc_int, NULL); 124 | define_cfunc(mod, "gc_run", mgc_run, mxc_none, NULL); 125 | define_cconst(mod, "argv", margv, new_type_list(mxc_string)); 126 | 127 | reg_gmodule(mod); 128 | } 129 | -------------------------------------------------------------------------------- /src/object/string.c: -------------------------------------------------------------------------------- 1 | /* implementation of string object */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "object/mstr.h" 7 | #include "object/system.h" 8 | #include "error/error.h" 9 | #include "mem.h" 10 | #include "vm.h" 11 | #include "mlib.h" 12 | 13 | MxcValue new_string(char *s, size_t len) { 14 | NEW_OBJECT(MString, ob, string_sys); 15 | 16 | ITERABLE(ob)->index = 0; 17 | ob->str = s; 18 | ob->isdyn = true; 19 | STRLEN(ob) = len; 20 | 21 | return mval_obj(ob); 22 | } 23 | 24 | MxcValue new_string_copy(char *s, size_t len) { 25 | NEW_OBJECT(MString, ob, string_sys); 26 | 27 | ob->str = malloc(sizeof(char) * (len + 1)); 28 | memcpy(ob->str, s, len); 29 | ob->str[len] = '\0'; 30 | 31 | ob->isdyn = true; 32 | STRLEN(ob) = len; 33 | 34 | return mval_obj(ob); 35 | } 36 | 37 | MxcValue new_string_static(char *s, size_t len) { 38 | NEW_OBJECT(MString, ob, string_sys); 39 | 40 | ob->str = s; 41 | ob->isdyn = false; 42 | STRLEN(ob) = len; 43 | 44 | return mval_obj(ob); 45 | } 46 | 47 | MxcValue string_copy(MxcObject *s) { 48 | MString *n = (MString *)mxc_alloc(sizeof(MString)); 49 | MString *old = (MString *)s; 50 | *n = *old; 51 | 52 | char *olds = n->str; 53 | n->str = malloc(sizeof(char) * (STRLEN(n) + 1)); 54 | strcpy(n->str, olds); 55 | n->isdyn = true; 56 | 57 | return mval_obj(n); 58 | } 59 | 60 | static void string_gc_mark(MxcObject *ob) { 61 | if(OBJGCMARKED(ob)) return; 62 | OBJGCMARK(ob); 63 | } 64 | 65 | static void str_guard(MxcObject *ob) { 66 | OBJGCGUARD(ob); 67 | } 68 | 69 | static void str_unguard(MxcObject *ob) { 70 | OBJGCUNGUARD(ob); 71 | } 72 | 73 | static void string_dealloc(MxcObject *s) { 74 | MString *str = (MString *)s; 75 | if(str->isdyn) 76 | free(str->str); 77 | Mxc_free(s); 78 | } 79 | 80 | MxcValue str_index(MxcIterable *self, MxcValue index) { 81 | MString *str = (MString *)self; 82 | int32_t idx = V2I(index); 83 | if(idx < 0) { 84 | idx = STRLEN(str) + idx; 85 | } 86 | if(STRLEN(str) <= idx) { 87 | mxc_raise(EXC_OUTOFRANGE, "out of range"); 88 | return mval_invalid; 89 | } 90 | 91 | return new_string_copy(&str->str[idx], 1); 92 | } 93 | 94 | MxcValue str_index_set(MxcIterable *self, MxcValue index, MxcValue a) { 95 | MString *str = (MString *)self; 96 | MString *src = (MString *)V2O(a); 97 | int32_t idx = V2I(index); 98 | if(idx < 0) { 99 | idx = STRLEN(str) + idx; 100 | } 101 | if(STRLEN(str) <= idx) { 102 | mxc_raise(EXC_OUTOFRANGE, "out of range"); 103 | return mval_invalid; 104 | } 105 | 106 | if(STRLEN(src) == 0) { 107 | // TODO; 108 | } 109 | else if(STRLEN(src) == 1) { 110 | str->str[idx] = src->str[0]; 111 | } 112 | else { 113 | // TODO; 114 | } 115 | 116 | return a; 117 | } 118 | 119 | MxcValue str_concat(MString *a, MString *b) { 120 | size_t len = STRLEN(a) + STRLEN(b); 121 | char *res = malloc(sizeof(char) * (len + 1)); 122 | strcpy(res, a->str); 123 | strcat(res, b->str); 124 | 125 | return new_string(res, len); 126 | } 127 | 128 | static MxcValue strupcase(MString *s) { 129 | MString *v = (MString *)V2O(new_string_copy(s->str, STRLEN(s))); 130 | for(int i = 0; i < STRLEN(v); i++) { 131 | char c = v->str[i]; 132 | if('a' <= c && c <= 'z') { 133 | c -= 0x20; 134 | } 135 | v->str[i] = c; 136 | } 137 | 138 | return mval_obj(v); 139 | } 140 | 141 | static MxcValue mstrupcase(MxcValue *a, size_t na) { 142 | return strupcase((MString *)V2O(a[0])); 143 | } 144 | 145 | static MxcValue strdowncase(MString *s) { 146 | MString *v = (MString *)V2O(new_string_copy(s->str, STRLEN(s))); 147 | for(int i = 0; i < STRLEN(v); i++) { 148 | char c = v->str[i]; 149 | if('A' <= c && c <= 'Z') { 150 | c += 0x20; 151 | } 152 | v->str[i] = c; 153 | } 154 | 155 | return mval_obj(v); 156 | } 157 | 158 | static MxcValue mstrdowncase(MxcValue *a, size_t na) { 159 | return strdowncase((MString *)V2O(a[0])); 160 | } 161 | 162 | static MxcValue strsplit(MString *s, MString *d) { 163 | char tmp[STRLEN(s) + 1]; 164 | memset(tmp, 0, STRLEN(s) + 1); 165 | strcpy(tmp, s->str); 166 | char *p = strtok(tmp, d->str); 167 | MxcValue vl = new_list(4); 168 | MList *l = (MList *)V2O(vl); 169 | listadd(l, new_string_copy(p, strlen(p))); 170 | 171 | while(1) { 172 | p = strtok(NULL, d->str); 173 | if(p) { 174 | listadd(l, new_string_copy(p, strlen(p))); 175 | } 176 | else { 177 | break; 178 | } 179 | } 180 | 181 | return vl; 182 | } 183 | 184 | static MxcValue mstrsplit(MxcValue *a, size_t na) { 185 | return strsplit((MString *)V2O(a[0]), (MString *)V2O(a[1])); 186 | } 187 | 188 | static MxcValue strempty(MString *s) { 189 | if(STRLEN(s) == 0) { 190 | return mval_true; 191 | } 192 | else { 193 | return mval_false; 194 | } 195 | } 196 | 197 | static MxcValue mstrempty(MxcValue *a, size_t na) { 198 | return strempty((MString *)V2O(a[0])); 199 | } 200 | 201 | static MxcValue strclear(MString *s) { 202 | if(s->isdyn) { 203 | free(s->str); 204 | } 205 | s->isdyn = false; 206 | s->str = ""; 207 | STRLEN(s) = 0; 208 | return mval_null; 209 | } 210 | 211 | static MxcValue mstrclear(MxcValue *a, size_t na) { 212 | return strclear((MString *)V2O(a[0])); 213 | } 214 | 215 | static bool internal_str_eq(MxcObject *a, MxcObject *b) { 216 | char *a_cstr = ((MString *)a)->str; 217 | char *b_cstr = ((MString *)b)->str; 218 | return strcmp(a_cstr, b_cstr) == 0; 219 | } 220 | 221 | static MxcValue str_eq(MString *a, MString *b) { 222 | return internal_str_eq(a, b)? mval_true : mval_false; 223 | } 224 | 225 | MxcValue mstr_eq(MxcValue *a, size_t na) { 226 | return str_eq((MString *)V2O(a[0]), (MString *)V2O(a[1])); 227 | } 228 | 229 | void str_cstr_append(MString *a, char *b, size_t blen) { 230 | size_t len = ITERABLE(a)->length + blen; 231 | if(a->isdyn) { 232 | a->str = realloc(a->str, sizeof(char) * (len + 1)); 233 | } 234 | else { 235 | char *buf = malloc(sizeof(char) * (len + 1)); 236 | strcpy(buf, a->str); 237 | a->str = buf; 238 | } 239 | 240 | strcat(a->str, b); 241 | ITERABLE(a)->length = len; 242 | a->isdyn = true; 243 | } 244 | 245 | void str_append(MString *a, MString *b) { 246 | str_cstr_append(a, b->str, ITERABLE(b)->length); 247 | } 248 | 249 | MxcValue string_tostring(MxcObject *ob) { 250 | return mval_obj(ob); 251 | } 252 | 253 | static MxcValue mstrlen(MxcValue *sp, size_t narg) { 254 | INTERN_UNUSE(narg); 255 | MString *ob = ostr(sp[0]); 256 | int len = ITERABLE(ob)->length; 257 | return mval_int(len); 258 | } 259 | 260 | /* FNV-1 algorithm */ 261 | static uint32_t str_hash32(MxcObject *ob) { 262 | MString *s = (MString *)ob; 263 | char *key = s->str; 264 | size_t len = STRLEN(s); 265 | 266 | uint32_t hash = 2166136261; 267 | 268 | for(size_t i = 0; i < len; i++) { 269 | hash = (hash ^ key[i]) * 16777619; 270 | } 271 | 272 | return hash; 273 | } 274 | 275 | struct mobj_system string_sys = { 276 | "string", 277 | NULL, 278 | string_tostring, 279 | string_dealloc, 280 | string_copy, 281 | string_gc_mark, 282 | str_guard, 283 | str_unguard, 284 | str_index, 285 | str_index_set, 286 | iterable_reset, 287 | iterable_next, 288 | iterable_stopped, 289 | str_hash32, 290 | internal_str_eq, 291 | }; 292 | 293 | void str_init() { 294 | MxcModule *mod = new_mxcmodule("string"); 295 | 296 | define_cfunc(mod, "eq", mstr_eq, FTYPE(mxc_bool, mxc_string, mxc_string)); 297 | define_cfunc(mod, "len", mstrlen, FTYPE(mxc_int, mxc_string)); 298 | define_cfunc(mod, "clear", mstrclear, FTYPE(mxc_none, mxc_string)); 299 | define_cfunc(mod, "empty", mstrempty, FTYPE(mxc_bool, mxc_string)); 300 | define_cfunc(mod, "upcase", mstrupcase, FTYPE(mxc_string, mxc_string)); 301 | define_cfunc(mod, "downcase", mstrdowncase, FTYPE(mxc_string, mxc_string)); 302 | Type *slist = new_type_list(mxc_string); 303 | define_cfunc(mod, "split", mstrsplit, FTYPE(slist, mxc_string, mxc_string)); 304 | 305 | reg_gmodule(mod); 306 | } 307 | -------------------------------------------------------------------------------- /src/object/struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "object/object.h" 5 | #include "object/system.h" 6 | #include "error/error.h" 7 | #include "object/mstruct.h" 8 | #include "mem.h" 9 | #include "vm.h" 10 | 11 | struct mobj_system strct_sys; 12 | 13 | MxcValue new_struct(int nfield) { 14 | MStrct *ob = (MStrct *)mxc_alloc(sizeof(MStrct)); 15 | ob->field = malloc(sizeof(MxcValue) * nfield); 16 | ob->nfield = nfield; 17 | SYSTEM(ob) = &strct_sys; 18 | 19 | return mval_obj(ob); 20 | } 21 | 22 | void strct_dealloc(MxcObject *ob) { 23 | MStrct *s = (MStrct *)ob; 24 | 25 | free(s->field); 26 | Mxc_free(s); 27 | } 28 | 29 | void strct_gc_mark(MxcObject *ob) { 30 | if(OBJGCMARKED(ob)) return; 31 | OBJGCMARK(ob); 32 | MStrct *s = (MStrct *)ob; 33 | 34 | for(int i = 0; i < s->nfield; i++) { 35 | mgc_mark(s->field[i]); 36 | } 37 | } 38 | 39 | void strct_guard(MxcObject *ob) { 40 | OBJGCGUARD(ob); 41 | MStrct *s = (MStrct *)ob; 42 | 43 | for(int i = 0; i < s->nfield; i++) { 44 | mgc_guard(s->field[i]); 45 | } 46 | } 47 | 48 | void strct_unguard(MxcObject *ob) { 49 | OBJGCUNGUARD(ob); 50 | MStrct *s = (MStrct *)ob; 51 | 52 | for(int i = 0; i < s->nfield; i++) { 53 | mgc_unguard(s->field[i]); 54 | } 55 | } 56 | 57 | MxcValue strct_copy(MxcObject *s) { 58 | MStrct *ob = (MStrct *)mxc_alloc(sizeof(MStrct)); 59 | memcpy(ob, s, sizeof(MStrct)); 60 | 61 | MxcValue *old_f = ob->field; 62 | ob->field = malloc(sizeof(MxcValue) * ob->nfield); 63 | for(size_t i = 0; i < ob->nfield; ++i) { 64 | ob->field[i] = mval_copy(old_f[i]); 65 | } 66 | 67 | return mval_obj(ob); 68 | } 69 | 70 | MxcValue strct_tostring(MxcObject *ob) { 71 | MStrct *s = (MStrct *)ob; 72 | if(s->nfield == 0) { 73 | return new_string_static("{}", 2); 74 | } 75 | GC_GUARD(s); 76 | MxcValue res = new_string_static("{", 1); 77 | mgc_guard(res); 78 | for(int i = 0; i < s->nfield; i++) { 79 | if(i > 0) { 80 | str_cstr_append(ostr(res), ", ", 2); 81 | } 82 | str_append(ostr(res), ostr(mval2str(s->field[i]))); 83 | } 84 | str_cstr_append(ostr(res), "}", 1); 85 | 86 | GC_UNGUARD(s); 87 | mgc_unguard(res); 88 | 89 | return res; 90 | } 91 | 92 | struct mobj_system strct_sys = { 93 | "struct", 94 | NULL, 95 | strct_tostring, 96 | strct_dealloc, 97 | strct_copy, 98 | strct_gc_mark, 99 | strct_guard, 100 | strct_unguard, 101 | 0, 102 | 0, 103 | 0, 104 | 0, 105 | 0, 106 | 0, 107 | }; 108 | -------------------------------------------------------------------------------- /src/object/table.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "object/mtable.h" 5 | #include "object/system.h" 6 | #include "object/mexception.h" 7 | #include "object/mstr.h" 8 | #include "mem.h" 9 | 10 | static MxcValue table_tostring(MxcObject *); 11 | 12 | static Type *table_ty; 13 | 14 | NEW_EXCEPTION(exc_unknownkey, "key error"); 15 | #define EXC_UNKNOWN_KEY (&exc_unknownkey) 16 | 17 | static int primes[] = { 18 | 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093 19 | }; 20 | 21 | static int nslot_from(int c) { 22 | static int nprimes = sizeof(primes) / sizeof(int); 23 | for(int i = 0; i < nprimes; i++) { 24 | if(c < primes[i]) 25 | return primes[i]; 26 | } 27 | 28 | return 0; 29 | } 30 | 31 | static struct mentry *new_entry(MxcValue k, MxcValue v) { 32 | struct mentry *e = malloc(sizeof(struct mentry)); 33 | e->key = k; 34 | e->val = v; 35 | e->next = NULL; 36 | return e; 37 | } 38 | 39 | MxcValue new_table_capa(int capa) { 40 | NEW_OBJECT(MTable, table, table_sys); 41 | 42 | int nslot = nslot_from(capa); 43 | table->e = calloc(1, sizeof(struct mentry *) * nslot); 44 | table->nslot = nslot; 45 | table->nentry = 0; 46 | table->default_val = mval_invalid; 47 | 48 | return mval_obj(table); 49 | } 50 | 51 | static struct mentry *echainadd(struct mentry *e, struct mentry *new) { 52 | new->next = e; 53 | return new; 54 | } 55 | 56 | static void extendtable(MTable *t) { 57 | int oldnslot = t->nslot; 58 | t->nslot = nslot_from(t->nentry); 59 | t->nentry = 0; 60 | struct mentry **old = t->e; 61 | t->e = calloc(1, sizeof(struct mentry *) * t->nslot); 62 | 63 | struct mentry *next; 64 | for(int i = 0; i < oldnslot; i++) { 65 | for(struct mentry *e = old[i]; e; e = next) { 66 | mtable_add(t, e->key, e->val); 67 | next = e->next; 68 | free(e); 69 | } 70 | } 71 | 72 | free(old); 73 | } 74 | 75 | void mtable_add(MTable *t, MxcValue key, MxcValue val) { 76 | if(++t->nentry > t->nslot) 77 | extendtable(t); 78 | 79 | uint32_t i = mval_hash32(key) % t->nslot; 80 | struct mentry *new = new_entry(key, val); 81 | if(t->e[i]) 82 | t->e[i] = echainadd(t->e[i], new); 83 | else 84 | t->e[i] = new; 85 | } 86 | 87 | static void table_dealloc(MxcObject *a) { 88 | MTable *t = (MTable *)a; 89 | Mxc_free(t); 90 | } 91 | 92 | static void table_gc_mark(MxcObject *a) { 93 | if(OBJGCMARKED(a)) return; 94 | OBJGCMARK(a); 95 | MTable *t = (MTable *)a; 96 | for(int i = 0; i < t->nslot; i++) { 97 | for(struct mentry *e = t->e[i]; e; e = e->next) { 98 | mgc_mark(e->key); 99 | mgc_mark(e->val); 100 | } 101 | } 102 | } 103 | 104 | static void table_gc_guard(MxcObject *a) { 105 | OBJGCGUARD(a); 106 | MTable *t = (MTable *)a; 107 | for(int i = 0; i < t->nslot; i++) { 108 | for(struct mentry *e = t->e[i]; e; e = e->next) { 109 | mgc_guard(e->key); 110 | mgc_guard(e->val); 111 | } 112 | } 113 | } 114 | 115 | static void table_gc_unguard(MxcObject *a) { 116 | OBJGCUNGUARD(a); 117 | MTable *t = (MTable *)a; 118 | for(int i = 0; i < t->nslot; i++) { 119 | for(struct mentry *e = t->e[i]; e; e = e->next) { 120 | mgc_unguard(e->key); 121 | mgc_unguard(e->val); 122 | } 123 | } 124 | } 125 | 126 | static MxcValue table_tostring(MxcObject *a) { 127 | MxcValue res; 128 | MTable *t = (MTable *)a; 129 | GC_GUARD(t); 130 | 131 | if(t->nentry == 0) { 132 | res = new_string_static("{}", 2); 133 | GC_UNGUARD(t); 134 | return res; 135 | } 136 | 137 | res = new_string_static("{", 1); 138 | mgc_guard(res); 139 | 140 | int c = 0; 141 | for(int i = 0; i < t->nslot; i++) { 142 | for(struct mentry *e = t->e[i]; e; e = e->next) { 143 | if(c++ > 0) 144 | str_cstr_append(ostr(res), ", ", 2); 145 | MxcValue key_s = mval2str(e->key); 146 | MxcValue val_s = mval2str(e->val); 147 | str_append(ostr(res), ostr(key_s)); 148 | str_cstr_append(ostr(res), "=>", 2); 149 | str_append(ostr(res), ostr(val_s)); 150 | } 151 | } 152 | 153 | str_cstr_append(ostr(res), "}", 1); 154 | 155 | GC_UNGUARD(t); 156 | mgc_unguard(res); 157 | 158 | return res; 159 | } 160 | 161 | void table_set_default(MTable *t, MxcValue def) { 162 | t->default_val = def; 163 | } 164 | 165 | MxcValue tablegetitem(MxcIterable *self, MxcValue index) { 166 | MTable *t = (MTable *)self; 167 | uint32_t i = mval_hash32(index) % t->nslot; 168 | 169 | struct mentry *e = NULL; 170 | for(e = t->e[i]; e; e = e->next) { 171 | if(mval_eq(e->key, index)) 172 | break; 173 | } 174 | 175 | if(e) { 176 | return e->val; 177 | } 178 | else if(check_value(t->default_val)) { 179 | return t->default_val; 180 | } 181 | else { 182 | mxc_raise(EXC_UNKNOWN_KEY, "unknown key: `%s`", mval2str(index)); 183 | return mval_invalid; 184 | } 185 | } 186 | 187 | MxcValue tablesetitem(MxcIterable *self, MxcValue index, MxcValue a) { 188 | MTable *t = (MTable *)self; 189 | uint32_t i = mval_hash32(index) % t->nslot; 190 | 191 | struct mentry *e = NULL; 192 | for(e = t->e[i]; e; e = e->next) { 193 | if(mval_eq(e->key, index)) 194 | break; 195 | } 196 | 197 | if(e) 198 | e->val = a; 199 | else 200 | mtable_add(t, index, a); 201 | 202 | return a; 203 | } 204 | 205 | struct mobj_attr table_attr[] = { 206 | { "default", offsetof(MTable, default_val), ATTR_READABLE | ATTR_WRITABLE, ATTY_MVALUE, NULL, offsetof(Type, val) }, 207 | { NULL }, 208 | }; 209 | 210 | struct mobj_system table_sys = { 211 | "table", 212 | table_attr, 213 | table_tostring, 214 | table_dealloc, 215 | 0, // TODO 216 | table_gc_mark, 217 | table_gc_guard, 218 | table_gc_unguard, 219 | tablegetitem, 220 | tablesetitem, 221 | 0, 222 | 0, 223 | 0, 224 | 0, 225 | }; 226 | -------------------------------------------------------------------------------- /src/object/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "object/object.h" 5 | #include "object/system.h" 6 | #include "object/mtime.h" 7 | #include "object/mstr.h" 8 | #include "mem.h" 9 | #include "mlib.h" 10 | 11 | Type *tim_t; 12 | 13 | char *asctime_r(const struct tm *tm, char *buf); 14 | struct tm *localtime_r(const time_t *timep, struct tm *result); 15 | 16 | MxcValue time_from_utime(time_t utime) { 17 | struct tm t; 18 | localtime_r(&utime, &t); 19 | 20 | NEW_OBJECT(MTime, newtime, time_sys); 21 | 22 | newtime->time = t; 23 | 24 | return mval_obj(newtime); 25 | } 26 | 27 | MxcValue nowtime() { 28 | time_t nowsec; 29 | time_t t = time(&nowsec); 30 | if(t == (time_t)-1) { 31 | /* raise error */ 32 | return mval_null; 33 | } 34 | 35 | struct tm nowtm; 36 | localtime_r(&nowsec, &nowtm); 37 | 38 | NEW_OBJECT(MTime, now, time_sys); 39 | 40 | now->time = nowtm; 41 | 42 | return mval_obj(now); 43 | } 44 | 45 | MxcValue m_nowtime(MxcValue *args, size_t na) { 46 | return nowtime(); 47 | } 48 | 49 | MxcValue timezone(MTime *t) { 50 | GC_GUARD(t); 51 | 52 | char buf[16] = {0}; 53 | strftime(buf, 16, "%Z", &t->time); 54 | 55 | MxcValue s = new_string_copy(buf, strlen(buf)); 56 | 57 | GC_UNGUARD(t); 58 | 59 | return s; 60 | } 61 | 62 | MxcValue m_timezone(MxcValue *args, size_t na) { 63 | return timezone((MTime *)V2O(args[0])); 64 | } 65 | 66 | MxcValue mtime_strftime(MTime *t, MString *fmt) { 67 | GC_GUARD(t); 68 | GC_GUARD(fmt); 69 | 70 | char buf[1024] = {0}; 71 | 72 | strftime(buf, 1024, fmt->str, &t->time); 73 | 74 | MxcValue s = new_string_copy(buf, strlen(buf)); 75 | 76 | GC_UNGUARD(t); 77 | GC_UNGUARD(fmt); 78 | 79 | return s; 80 | } 81 | 82 | MxcValue m_strftime(MxcValue *args, size_t na) { 83 | return mtime_strftime((MTime *)V2O(args[0]), (MString *)V2O(args[1])); 84 | } 85 | 86 | static MxcValue tm_tostring(MxcObject *ob) { 87 | MTime *t = (MTime *)ob; 88 | GC_GUARD(t); 89 | char buf[64] = {0}; 90 | 91 | strftime(buf, 64, "%Y-%m-%d %H:%M:%S %z", &t->time); 92 | 93 | MxcValue s = new_string_copy(buf, strlen(buf)); 94 | 95 | GC_UNGUARD(t); 96 | 97 | return s; 98 | } 99 | 100 | static void tm_gc_mark(MxcObject *ob) { 101 | if(OBJGCMARKED(ob)) return; 102 | OBJGCMARK(ob); 103 | } 104 | 105 | static void tm_guard(MxcObject *ob) { 106 | OBJGCGUARD(ob); 107 | } 108 | 109 | static void tm_unguard(MxcObject *ob) { 110 | OBJGCUNGUARD(ob); 111 | } 112 | 113 | static void tm_dealloc(MxcObject *s) { 114 | Mxc_free(s); 115 | } 116 | 117 | struct mobj_system time_sys = { 118 | "time", 119 | NULL, 120 | tm_tostring, 121 | tm_dealloc, 122 | 0, 123 | tm_gc_mark, 124 | tm_guard, 125 | tm_unguard, 126 | 0, 127 | 0, 128 | 0, 129 | 0, 130 | 0, 131 | obj_hash32, 132 | 0, 133 | 0, 134 | }; 135 | 136 | void time_init() { 137 | MxcModule *mod = new_mxcmodule("Time"); 138 | 139 | tim_t = userdef_type("Time", T_SHOWABLE); 140 | 141 | define_cfunc(mod, "nowtime", m_nowtime, FTYPE(tim_t)); 142 | define_cfunc(mod, "zone", m_timezone, FTYPE(mxc_string, tim_t)); 143 | define_cfunc(mod, "strftime", m_strftime, FTYPE(mxc_string, tim_t, mxc_string)); 144 | 145 | define_ctype(mod, tim_t); 146 | 147 | reg_gmodule(mod); 148 | } 149 | -------------------------------------------------------------------------------- /src/repl/repl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "maxc.h" 5 | #include "ast.h" 6 | #include "bytecode.h" 7 | #include "codegen.h" 8 | #include "error/error.h" 9 | #include "lexer.h" 10 | #include "parser.h" 11 | #include "sema.h" 12 | #include "token.h" 13 | #include "type.h" 14 | #include "vm.h" 15 | #include "util.h" 16 | #include "object/object.h" 17 | #include "object/mstr.h" 18 | #include "literalpool.h" 19 | #include "gc.h" 20 | 21 | extern char *filename; 22 | extern Vector *ltable; 23 | extern char *code; 24 | extern size_t gc_time; 25 | #define MAX_GLOBAL_VARS 128 26 | 27 | void mxc_repl_run(const char *src, struct cgen *cg) { 28 | struct cgen *c = NULL; 29 | Vector *token = lexer_run(src, filename); 30 | struct mparser *pstate = parser_run(token); 31 | if(pstate->err) 32 | goto err; 33 | 34 | Vector *ast = pstate->ast; 35 | SemaResult sema_res = sema_analysis_repl(ast); 36 | if(sema_res.scope->err) 37 | goto err; 38 | 39 | c = compile_repl(ast, cg); 40 | 41 | #ifdef MXC_DEBUG 42 | puts(BOLD("--- literal pool ---")); 43 | lpooldump(c->ltable); 44 | puts(BOLD("--- codedump ---")); 45 | printf("iseq len: %d\n", c->iseq->len); 46 | /* 47 | printf("\e[2m"); 48 | for(size_t i = 0; i < c->iseq->len;) { 49 | codedump(c->iseq->code, &i, c->ltable); 50 | puts(""); 51 | } 52 | */ 53 | puts(STR_DEFAULT); 54 | puts(BOLD("--- exec result ---")); 55 | #endif 56 | 57 | VM *vm = curvm(); 58 | vm->gvars = c->gvars; 59 | vm->ctx->code = c->iseq->code; 60 | vm->ctx->pc = &c->iseq->code[0]; 61 | 62 | int res = vm_run(); 63 | 64 | if(sema_res.isexpr && res == 0) { 65 | extern enum stack_cache_state scstate; 66 | MxcValue top = (scstate & 1)? screg_a : scstate? screg_b : POP(); 67 | scstate = (((int)scstate - 2) <= 0? 0 : scstate - 2); 68 | char *dump = ostr(mval2str(top))->str; 69 | printf("%s : %s\n", dump, sema_res.tyname); 70 | } 71 | 72 | err: 73 | free(pstate); 74 | free(c); 75 | } 76 | 77 | int mxc_main_repl() { 78 | printf("Welcome to maxc repl mode!\n"); 79 | printf("maxc Version %s\n", MXC_VERSION); 80 | printf("use exit(int) or Ctrl-D to exit\n"); 81 | 82 | filename = ""; 83 | size_t cursor; 84 | struct cgen *c = newcgen_glb(MAX_GLOBAL_VARS); 85 | vm_open(NULL, NULL, MAX_GLOBAL_VARS, c->ltable, NULL); 86 | 87 | for(;;) { 88 | cursor = 0; 89 | printf(">> "); 90 | 91 | ReadStatus rs = intern_readline(1024, &cursor, ";\n", 2); 92 | if(rs.err.eof) { /* repl end */ 93 | putchar('\n'); 94 | return 0; 95 | } 96 | if(rs.err.toolong) { 97 | error("Too long input"); 98 | continue; 99 | } 100 | 101 | code = rs.str; 102 | mxc_repl_run(rs.str, c); 103 | 104 | free(rs.str); 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /src/runtime/context.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "maxc.h" 4 | #include "object/object.h" 5 | #include "context.h" 6 | #include "error/error.h" 7 | 8 | MContext *new_econtext(mptr_t *code, size_t nlvars, DebugInfo *d, MContext *prev) { 9 | MContext *c = malloc(sizeof(MContext)); 10 | c->prev = prev; 11 | c->code = code; 12 | c->basepc = c->pc = &code[0]; 13 | if(nlvars != 0) { 14 | c->lvars = malloc(sizeof(MxcValue) * nlvars); 15 | } 16 | else { 17 | c->lvars = NULL; 18 | } 19 | c->nlvars = nlvars; 20 | c->exc = NULL; 21 | c->err_handling_enabled = 0; 22 | c->d = d; 23 | 24 | return c; 25 | } 26 | 27 | void delete_context(MContext *c) { 28 | free(c->lvars); 29 | free(c); 30 | } 31 | -------------------------------------------------------------------------------- /src/runtime/execarg.c: -------------------------------------------------------------------------------- 1 | #include "execarg.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/runtime/gc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "object/object.h" 5 | #include "object/system.h" 6 | #include "gc.h" 7 | #include "vm.h" 8 | 9 | GCHeap root; 10 | GCHeap *tailp = NULL; 11 | 12 | clock_t gc_time; 13 | 14 | extern MxcValue screg_a; 15 | extern MxcValue screg_b; 16 | 17 | void heap_dump() { 18 | GCHeap *ptr = &root; 19 | int counter = 0; 20 | puts("----- [heap dump] -----"); 21 | while(ptr) { 22 | bool marked = OBJGCMARKED(ptr->obj); 23 | printf("%s%d: ", marked ? "[marked]" : "", counter++); 24 | printf("%s\n", SYSTEM(ptr->obj)->type_name); 25 | ptr = ptr->next; 26 | } 27 | puts("-----------------------"); 28 | } 29 | 30 | size_t heap_length() { 31 | GCHeap *ptr = &root; 32 | size_t i = 0; 33 | while(ptr) { 34 | ptr = ptr->next; 35 | ++i; 36 | } 37 | return i; 38 | } 39 | 40 | void stack_dump_weak() { 41 | VM *vm = curvm(); 42 | MxcValue *base = vm->stackbase; 43 | MxcValue *cur = vm->stackptr; 44 | MxcValue val; 45 | puts("---stackweak---"); 46 | while(base < cur) { 47 | val = *--cur; 48 | if(isobj(val)) { 49 | printf("%p:", V2O(val)); 50 | printf("%p\n", SYSTEM(V2O(val))); 51 | } 52 | } 53 | puts("---------------"); 54 | } 55 | 56 | static void gc_mark_all() { 57 | VM *vm = curvm(); 58 | MxcValue *base = vm->stackbase; 59 | MxcValue *cur = vm->stackptr; 60 | MxcValue val; 61 | 62 | switch(scstate) { 63 | case SCAX: mgc_mark(screg_a); break; 64 | case SCBX: mgc_mark(screg_b); break; 65 | case SCBA: 66 | case SCAB: 67 | mgc_mark(screg_a); 68 | mgc_mark(screg_b); 69 | break; 70 | default: break; 71 | } 72 | 73 | while(base < cur) { 74 | val = *--cur; 75 | mgc_mark(val); 76 | } 77 | for(size_t i = 0; i < vm->ngvars; ++i) { 78 | val = vm->gvars[i]; 79 | mgc_mark(val); 80 | } 81 | 82 | MContext *c = vm->ctx; 83 | while(c) { 84 | for(size_t i = 0; i < c->nlvars; i++) { 85 | val = c->lvars[i]; 86 | mgc_mark(val); 87 | } 88 | c = c->prev; 89 | } 90 | } 91 | 92 | static void gc_sweep() { 93 | GCHeap *ptr = &root; 94 | GCHeap *prev = NULL; 95 | GCHeap *next = NULL; 96 | MxcObject *ob; 97 | while(ptr) { 98 | ob = ptr->obj; 99 | next = ptr->next; 100 | if(OBJGCMARKED(ob) || OBJGCGUARDED(ob)) { 101 | OBJGCUNMARK(ob); 102 | prev = ptr; 103 | } 104 | else { 105 | SYSTEM(ob)->dealloc(ob); 106 | if(prev) prev->next = ptr->next; 107 | else root = *ptr->next; 108 | free(ptr); 109 | } 110 | ptr = next; 111 | } 112 | 113 | tailp = prev; 114 | } 115 | 116 | void gc_run() { 117 | clock_t start, end; 118 | start = clock(); 119 | 120 | gc_mark_all(); 121 | gc_sweep(); 122 | 123 | end = clock(); 124 | gc_time += end - start; 125 | } 126 | -------------------------------------------------------------------------------- /src/runtime/literalpool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "literalpool.h" 5 | #include "maxc.h" 6 | 7 | Literal *New_Literal() { 8 | Literal *l = xmalloc(sizeof(Literal)); 9 | 10 | return l; 11 | } 12 | 13 | Literal *New_Literal_With_Str(char *str) { 14 | Literal *l = xmalloc(sizeof(Literal)); 15 | l->kind = LIT_STR; 16 | l->str = str; 17 | 18 | return l; 19 | } 20 | 21 | Literal *New_Literal_Long(int64_t i64) { 22 | Literal *l = xmalloc(sizeof(Literal)); 23 | l->kind = LIT_LONG; 24 | l->lnum = i64; 25 | 26 | return l; 27 | } 28 | 29 | Literal *New_Literal_With_Fnumber(double f) { 30 | Literal *l = xmalloc(sizeof(Literal)); 31 | l->kind = LIT_FNUM; 32 | l->fnumber = f; 33 | 34 | return l; 35 | } 36 | 37 | Literal *New_Literal_With_Userfn(userfunction *u) { 38 | Literal *l = xmalloc(sizeof(Literal)); 39 | l->kind = LIT_FUNC; 40 | l->func = u; 41 | 42 | return l; 43 | } 44 | 45 | Literal *New_Literal_Object(MxcValue o) { 46 | Literal *l = xmalloc(sizeof(Literal)); 47 | l->kind = LIT_RAWOBJ; 48 | l->raw = o; 49 | 50 | return l; 51 | } 52 | 53 | int lpool_push_str(Vector *table, char *s) { 54 | for(int i = 0; i < table->len; ++i) { 55 | Literal *cur = (Literal *)table->data[i]; 56 | 57 | if(cur->kind != LIT_STR) continue; 58 | if(strcmp(cur->str, s) == 0) return i; 59 | } 60 | 61 | int key = table->len; 62 | vec_push(table, New_Literal_With_Str(s)); 63 | 64 | return key; 65 | } 66 | 67 | int lpool_push_long(Vector *table, int64_t i64) { 68 | for(int i = 0; i < table->len; ++i) { 69 | Literal *cur = (Literal *)table->data[i]; 70 | 71 | if(cur->kind != LIT_LONG) continue; 72 | if(cur->lnum == i64) return i; 73 | } 74 | 75 | int key = table->len; 76 | vec_push(table, New_Literal_Long(i64)); 77 | 78 | return key; 79 | } 80 | 81 | int lpool_push_float(Vector *table, double fnum) { 82 | for(int i = 0; i < table->len; ++i) { 83 | Literal *cur = (Literal *)table->data[i]; 84 | 85 | if(cur->kind != LIT_FNUM) continue; 86 | if(cur->fnumber == fnum) return i; 87 | } 88 | 89 | int key = table->len; 90 | vec_push(table, New_Literal_With_Fnumber(fnum)); 91 | 92 | return key; 93 | } 94 | 95 | int lpool_push_userfunc(Vector *table, userfunction *func) { 96 | int key = table->len; 97 | vec_push(table, New_Literal_With_Userfn(func)); 98 | 99 | return key; 100 | } 101 | 102 | int lpool_push_object(Vector *table, MxcValue ob) { 103 | for(int i = 0; i < table->len; ++i) { 104 | Literal *cur = (Literal *)table->data[i]; 105 | 106 | if(cur->kind != LIT_RAWOBJ) continue; 107 | if(V2O(cur->raw) == V2O(ob)) return i; 108 | } 109 | 110 | int key = table->len; 111 | vec_push(table, New_Literal_Object(ob)); 112 | 113 | return key; 114 | } 115 | 116 | void lpooldump(Vector *table) { 117 | for(int i = 0; i < table->len; ++i) { 118 | Literal *a = (Literal *)table->data[i]; 119 | 120 | switch(a->kind) { 121 | case LIT_STR: 122 | printf(" str: '%s' ", a->str); 123 | break; 124 | case LIT_FNUM: 125 | printf(" fnum: %lf ", a->fnumber); 126 | break; 127 | case LIT_LONG: 128 | printf(" long: %ld ", a->lnum); 129 | break; 130 | case LIT_FUNC: 131 | printf(" func "); 132 | break; 133 | case LIT_RAWOBJ: 134 | printf(" rawobject "); 135 | break; 136 | } 137 | } 138 | puts(""); 139 | } 140 | -------------------------------------------------------------------------------- /src/runtime/mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "mem.h" 6 | #include "internal.h" 7 | #include "gc.h" 8 | 9 | size_t allocated_mem = 0; 10 | size_t threshold = 1024; 11 | 12 | #ifdef OBJECT_POOL 13 | ObjectPool obpool; 14 | 15 | #define NALLOC 1024 16 | 17 | void New_Objectpool() { 18 | obpool.pool = malloc(sizeof(MxcObject *) * NALLOC); 19 | obpool.reserved = obpool.len = NALLOC; 20 | 21 | for(int i = 0; i < NALLOC; ++i) { 22 | obpool.pool[i] = malloc(sizeof(union obalign)); 23 | } 24 | } 25 | 26 | /* free */ 27 | void obpool_push(MxcObject *ob) { 28 | if(obpool.reserved == obpool.len) { 29 | obpool.reserved *= 2; 30 | obpool.pool = realloc(obpool.pool, sizeof(MxcObject *) * obpool.reserved); 31 | } 32 | memset(ob, 0, sizeof(union obalign)); 33 | 34 | obpool.pool[obpool.len++] = ob; 35 | } 36 | 37 | static MxcObject *obpool_pop() { return obpool.pool[--obpool.len]; } 38 | 39 | #endif /* OBJECT_POOL */ 40 | 41 | MxcObject *mxc_alloc(size_t s) { 42 | if(++allocated_mem >= threshold) { 43 | allocated_mem = 0; 44 | gc_run(); 45 | } 46 | 47 | #ifdef OBJECT_POOL 48 | INTERN_UNUSE(s); 49 | if(obpool.len == 0) { 50 | New_Objectpool(); 51 | } 52 | MxcObject *ob = obpool_pop(); 53 | #else 54 | MxcObject *ob = calloc(1, s); 55 | if(!ob) { 56 | gc_run(); 57 | ob = malloc(s); 58 | if(!ob) { 59 | return NULL; 60 | } 61 | } 62 | #endif /* OBJECT_POOL */ 63 | 64 | if(!tailp) { /* first call */ 65 | root.obj = ob; 66 | root.next = NULL; 67 | tailp = &root; 68 | } 69 | else { 70 | GCHeap *new = malloc(sizeof(GCHeap)); 71 | new->obj = ob; 72 | new->next = NULL; 73 | tailp->next = new; 74 | tailp = new; 75 | } 76 | 77 | return ob; 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/util/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "util.h" 5 | #include "error/error.h" 6 | 7 | Vector *new_vector() { 8 | Vector *self = xmalloc(sizeof(Vector)); 9 | 10 | self->data = xmalloc(sizeof(void *) * 16); 11 | self->len = 0; 12 | self->reserved = 16; 13 | 14 | return self; 15 | } 16 | 17 | Vector *new_vector_capa(int size) { 18 | Vector *self = xmalloc(sizeof(Vector)); 19 | 20 | self->data = xmalloc(sizeof(void *) * size); 21 | self->len = 0; 22 | self->reserved = size; 23 | 24 | for(int i = 0; i < size; ++i) { 25 | self->data[i] = NULL; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | void del_vector(Vector *self) { 32 | free(self->data); 33 | free(self); 34 | } 35 | 36 | void vec_push(Vector *self, void *d) { 37 | if(self->len == self->reserved) { 38 | self->reserved *= 2; 39 | self->data = realloc(self->data, sizeof(void *) * self->reserved); 40 | } 41 | 42 | self->data[self->len++] = d; 43 | } 44 | void *vec_pop(Vector *self) { 45 | #ifdef MXC_DEBUG 46 | if(self->len == 0) { 47 | error("vector is empty"); 48 | return NULL; 49 | } 50 | #endif 51 | 52 | return self->data[--self->len]; 53 | } 54 | 55 | void vec_set_at(Vector *vec, int at, void *d) { 56 | if(at >= vec->reserved) { 57 | vec->reserved = at * 2; 58 | vec->data = realloc(vec->data, sizeof(void *) * vec->reserved); 59 | } 60 | vec->data[at] = d; 61 | } 62 | 63 | void vec_extend(Vector *vec, int size) { 64 | vec->data = realloc(vec->data, sizeof(void *) * size); 65 | vec->reserved = size; 66 | } 67 | 68 | void *vec_last(Vector *self) { return self->data[self->len - 1]; } 69 | 70 | int get_digit(int num) { 71 | char buf[100]; 72 | 73 | return sprintf(buf, "%d", num); 74 | } 75 | 76 | char *read_file(const char *path) { 77 | FILE *src_file = fopen(path, "r"); 78 | if(!src_file) { 79 | return NULL; 80 | } 81 | 82 | fseek(src_file, 0, SEEK_END); 83 | size_t fsize = ftell(src_file); 84 | fseek(src_file, 0, SEEK_SET); 85 | 86 | char *src = calloc(1, fsize + 1); 87 | 88 | if(fread(src, 1, fsize, src_file) < fsize) { 89 | error("Error reading file"); 90 | } 91 | 92 | fclose(src_file); 93 | 94 | return src; 95 | } 96 | -------------------------------------------------------------------------------- /test/andtest.mxc: -------------------------------------------------------------------------------- 1 | def test(a: int, b: int, c: int, d: int): bool { 2 | if a == b && c == d{ 3 | return true; 4 | } 5 | 6 | return false; 7 | } 8 | 9 | assert test(100, 100, 50, 50); 10 | assert !test(100, 20, 50, 50); 11 | -------------------------------------------------------------------------------- /test/arg.mxc: -------------------------------------------------------------------------------- 1 | def test(a, b, c, d: int): int = a + b + c + d; 2 | 3 | println test(100, 20, 30, 50); 4 | assert test(100, 20, 30, 50) == 200; 5 | -------------------------------------------------------------------------------- /test/argv.mxc: -------------------------------------------------------------------------------- 1 | echo argv; 2 | -------------------------------------------------------------------------------- /test/arith.mxc: -------------------------------------------------------------------------------- 1 | assert 10 * 200 * 9 == 18000; 2 | assert 200 / (10 + 10) == 10; 3 | assert 100 - 20 * 10 == -100; 4 | assert 20 + 20 - 10 - 20 == 10; 5 | -------------------------------------------------------------------------------- /test/bignum.mxc: -------------------------------------------------------------------------------- 1 | def test_big_add() { 2 | let a = 891749832710498174827472 + 4783271840721421783974921; 3 | let b = 428146327145219647214879 + -28146327145219647214879; 4 | let c = -28146327145219647214879 + 428146327145219647214879; 5 | let d = -891749832710498174827472 + -4783271840721421783974921; 6 | 7 | assert a == 5675021673431919958802393; 8 | assert b == 400000000000000000000000; 9 | assert c == 400000000000000000000000; 10 | assert d == -5675021673431919958802393; 11 | } 12 | 13 | def test_big_sub() { 14 | let a = 428146327145219647214879 - 28146327145219647214879; 15 | let b = -891749832710498174827472 - 4783271840721421783974921; 16 | let c = 891749832710498174827472 - -4783271840721421783974921; 17 | let d = -28146327145219647214879 - -428146327145219647214879; 18 | 19 | assert a == 400000000000000000000000; 20 | assert b == -5675021673431919958802393; 21 | assert c == 5675021673431919958802393; 22 | assert d == 400000000000000000000000; 23 | } 24 | 25 | def test_big_mul() { 26 | let a = 73472148014787328174087081784 * 78943178973516587687531; 27 | let b = -73472148014787328174087081784 * 78943178973516587687531; 28 | let c = 73472148014787328174087081784 * -78943178973516587687531; 29 | let d = -73472148014787328174087081784 * -78943178973516587687531; 30 | 31 | assert a == 5800124930300057505620336136415813778007816634035304; 32 | assert b == -5800124930300057505620336136415813778007816634035304; 33 | assert c == -5800124930300057505620336136415813778007816634035304; 34 | assert d == 5800124930300057505620336136415813778007816634035304; 35 | } 36 | 37 | test_big_add(); 38 | test_big_sub(); 39 | test_big_mul(); 40 | -------------------------------------------------------------------------------- /test/bool.mxc: -------------------------------------------------------------------------------- 1 | let a = 200; 2 | let b = 100; 3 | 4 | assert (a > 10) == true; 5 | assert (a < b) == false; 6 | -------------------------------------------------------------------------------- /test/comment.mxc: -------------------------------------------------------------------------------- 1 | let a: int = 100; 2 | // let a: int = 299; 3 | 4 | assert a == 100; 5 | -------------------------------------------------------------------------------- /test/file.mxc: -------------------------------------------------------------------------------- 1 | let f = open("./test/file/a.txt"); 2 | let res = ""; 3 | while !f.eof { 4 | res += f.readline; 5 | } 6 | 7 | assert res.eq "YURUYURI\nYUYUSHIKI\nHIDAMARI SKETCH\nKILLME BABY\nKIN-IRO MOSAIC\n" 8 | -------------------------------------------------------------------------------- /test/file/a.txt: -------------------------------------------------------------------------------- 1 | YURUYURI 2 | YUYUSHIKI 3 | HIDAMARI SKETCH 4 | KILLME BABY 5 | KIN-IRO MOSAIC 6 | -------------------------------------------------------------------------------- /test/float.mxc: -------------------------------------------------------------------------------- 1 | assert 16.00 == 16.00; 2 | assert 31.81 + 19.1 * 7.3 == 171.24; 3 | -------------------------------------------------------------------------------- /test/fntest.mxc: -------------------------------------------------------------------------------- 1 | def test1(n: int): int { return n - 50; } 2 | 3 | def test2(n: int) = 10 * n; 4 | 5 | def main(): int { 6 | return 100.test1().test2(); 7 | } 8 | 9 | assert main() == 500; 10 | -------------------------------------------------------------------------------- /test/for.mxc: -------------------------------------------------------------------------------- 1 | use std@upto; 2 | 3 | let sum = 0; 4 | for i in 1.upto(9) { 5 | for j in 1.upto(9) { 6 | sum = sum + i * j; 7 | } 8 | } 9 | assert sum == 2025; 10 | 11 | sum = 0; 12 | for i in [10,20,30,40,50] { 13 | if 40 <= i { 14 | break; 15 | } 16 | sum += i; 17 | } 18 | assert sum == 60; 19 | 20 | sum = 0; 21 | for i in [[10,20,30], [10,20,30]] { 22 | for j in i { 23 | sum += j; 24 | } 25 | } 26 | assert sum == 120; 27 | -------------------------------------------------------------------------------- /test/func.mxc: -------------------------------------------------------------------------------- 1 | def add(a: int, b: int): int { 2 | return a + b; 3 | } 4 | def mul(a: int, b: int) = a * b; 5 | 6 | assert 10.mul(10).add(400) == 500; 7 | -------------------------------------------------------------------------------- /test/hashtable.mxc: -------------------------------------------------------------------------------- 1 | let a = #["a": 200, "aa": 210]; 2 | 3 | assert a["a"] == 200; 4 | assert a["aa"] == 210; 5 | 6 | a["aa"] = 2105; 7 | 8 | assert a["a"] == 200; 9 | assert a["aa"] == 2105; 10 | 11 | a["bbc"] = 4290; 12 | 13 | assert a["a"] == 200; 14 | assert a["aa"] == 2105; 15 | assert a["bbc"] == 4290; 16 | 17 | a["ccde"] = 2948; 18 | 19 | assert a["a"] == 200; 20 | assert a["aa"] == 2105; 21 | assert a["bbc"] == 4290; 22 | assert a["ccde"] == 2948; 23 | 24 | a.default = 1000; 25 | 26 | assert a["a"] == 200; 27 | assert a["aa"] == 2105; 28 | assert a["bbc"] == 4290; 29 | assert a["ccde"] == 2948; 30 | assert a["notfoundkey"] == 1000; 31 | -------------------------------------------------------------------------------- /test/if.mxc: -------------------------------------------------------------------------------- 1 | let a = 0; 2 | let b = 100; 3 | let c = 10; 4 | 5 | if b == 100 { 6 | a = 96000; 7 | if c != 0 { 8 | c = 10000; 9 | } 10 | } 11 | else { 12 | a = 0; 13 | c = 0; 14 | } 15 | 16 | assert a == 96000; 17 | assert c == 10000; 18 | 19 | if b != 100 { 20 | c = 1; 21 | } 22 | else { 23 | if a < 95999 { 24 | c = 1; 25 | } 26 | else { 27 | c = 0; 28 | } 29 | } 30 | 31 | assert c == 0; 32 | -------------------------------------------------------------------------------- /test/import.mxc: -------------------------------------------------------------------------------- 1 | use math@abs; 2 | 3 | let a = -100; 4 | let b = 20; 5 | 6 | assert a.abs == 100; 7 | assert b.abs == 20; 8 | -------------------------------------------------------------------------------- /test/inttof.mxc: -------------------------------------------------------------------------------- 1 | let a: int = 10; 2 | 3 | println(20.0 + a.tofloat + 32.1); 4 | assert 20.0 + a.tofloat() + 32.1 == 62.1; 5 | -------------------------------------------------------------------------------- /test/let.mxc: -------------------------------------------------------------------------------- 1 | let a: int = 100; 2 | let b = 100.0; 3 | 4 | assert a == 100 && b == 100.0; 5 | -------------------------------------------------------------------------------- /test/list.mxc: -------------------------------------------------------------------------------- 1 | // [int] 2 | let a = [100,200,300,400,500]; 3 | assert a.len == 5; 4 | assert a.pop == 500; 5 | a.add 1000; 6 | let sum = 0; 7 | for i in a { 8 | sum += i; 9 | } 10 | assert sum == 2000; 11 | let b = a.reversed; 12 | assert b[0] == 1000; 13 | a.clear; 14 | assert a.len == 0; 15 | a.add 600; 16 | a.add 700; 17 | a.add 800; 18 | a.del_at 1; 19 | assert a[1] == 800; 20 | assert a.len == 2; 21 | -------------------------------------------------------------------------------- /test/logic.mxc: -------------------------------------------------------------------------------- 1 | assert !(10 < 0); 2 | assert 10 < 20; 3 | assert !(200 == 300); 4 | assert !(10 != 10); 5 | -------------------------------------------------------------------------------- /test/noret.mxc: -------------------------------------------------------------------------------- 1 | def main() { 2 | assert 1 == 1; 3 | } 4 | 5 | main(); 6 | -------------------------------------------------------------------------------- /test/not.mxc: -------------------------------------------------------------------------------- 1 | let a = 10; 2 | 3 | assert !(a != 10); 4 | -------------------------------------------------------------------------------- /test/obid.mxc: -------------------------------------------------------------------------------- 1 | let a: int = 10; 2 | 3 | assert a.objectid != 0; 4 | -------------------------------------------------------------------------------- /test/object.mxc: -------------------------------------------------------------------------------- 1 | object Rect { 2 | width: int, 3 | height: int 4 | } 5 | 6 | def area(r: Rect): int { 7 | return r.width * r.height; 8 | } 9 | 10 | def add(r: Rect): int { 11 | return r.width + r.height; 12 | } 13 | 14 | let recta = new Rect; 15 | recta.width = 50; 16 | recta.height = 40; 17 | 18 | assert 2000 == recta.area; 19 | assert 90 == recta.add; 20 | -------------------------------------------------------------------------------- /test/onelinefn.mxc: -------------------------------------------------------------------------------- 1 | def x50(n: int) = n * 50; 2 | 3 | assert 100.x50 == 5000; 4 | -------------------------------------------------------------------------------- /test/overload.mxc: -------------------------------------------------------------------------------- 1 | def test() = 0; 2 | 3 | def test(a: int) = a; 4 | 5 | def test(a: int, b: int) = a + b; 6 | 7 | assert test() == 0; 8 | assert 10.test == 10; 9 | assert 10.test(20) == 30; 10 | -------------------------------------------------------------------------------- /test/rec.mxc: -------------------------------------------------------------------------------- 1 | def fibo(n: int): int { 2 | if n <= 1 { 3 | return n; 4 | } 5 | else { 6 | return fibo(n - 1) + fibo(n - 2); 7 | } 8 | } 9 | 10 | assert 20.fibo == 6765; 11 | -------------------------------------------------------------------------------- /test/scope.mxc: -------------------------------------------------------------------------------- 1 | def pow2(n: int): int { 2 | let a = 0; 3 | let res = 1; 4 | 5 | while a < n { 6 | res = res * 2; 7 | a = a + 1; 8 | } 9 | 10 | return res; 11 | } 12 | 13 | let a = 10; 14 | 15 | assert a.pow2 == 1024; 16 | 17 | -------------------------------------------------------------------------------- /test/string.mxc: -------------------------------------------------------------------------------- 1 | let a = "hello "; 2 | let b = "world"; 3 | 4 | assert (a+b).eq "hello world"; 5 | assert a[2].eq "l"; 6 | 7 | assert (a+b).len == 11; 8 | assert "".len == 0; 9 | 10 | assert "".empty == true; 11 | assert a.empty == false; 12 | a.clear; 13 | assert a.empty == true; 14 | 15 | assert "yuruyuri".upcase.eq "YURUYURI"; 16 | assert "Yuruyuri".upcase.eq "YURUYURI"; 17 | assert "YURUYURI".downcase.eq "yuruyuri"; 18 | assert "Yuruyuri".downcase.eq "yuruyuri"; 19 | 20 | assert "Hello, World".split(",")[0].eq "Hello"; 21 | assert "Hello, World".split(",")[1].eq " World"; 22 | -------------------------------------------------------------------------------- /test/struct.mxc: -------------------------------------------------------------------------------- 1 | object Test { 2 | sakana: int, 3 | color: float 4 | } 5 | 6 | let dori = new Test; 7 | 8 | dori.sakana = 400; 9 | dori.color = 100.0; 10 | 11 | assert dori.sakana == 400; 12 | assert dori.color == 100.0; 13 | -------------------------------------------------------------------------------- /test/switch.mxc: -------------------------------------------------------------------------------- 1 | let n = 2; 2 | let a: int; 3 | switch n { 4 | case 1: a = 100; 5 | case 2: a = 200; 6 | else: a = 100000; 7 | } 8 | 9 | assert a == 200; 10 | 11 | let who = "ben"; 12 | switch who { 13 | case "nick": assert false; 14 | case "ben": assert true; 15 | else: assert false; 16 | } 17 | 18 | let f = 10.0; 19 | switch f { 20 | case 0.0: assert false; 21 | case 30.0: assert false; 22 | else: assert true; 23 | } 24 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | fail=0 2 | 3 | for file in `\find ./test -name '*.mxc'`; do 4 | echo -n $file :\ 5 | ./maxc $file > /dev/null 6 | if [ $? -eq 0 ]; then 7 | echo "passed" 8 | else 9 | echo "failed" 10 | fail=1 11 | fi 12 | done 13 | 14 | if [ $fail -eq 0 ]; then 15 | echo "(*'-') < all passed" 16 | return 0; 17 | else 18 | echo "(*-\"-) < test failed" 19 | return 1; 20 | fi 21 | -------------------------------------------------------------------------------- /test/ufcstest.mxc: -------------------------------------------------------------------------------- 1 | def double(n: int) = n * 2; 2 | def add2(n: int) = n + 2; 3 | def minus(n: int, m: int) = n - m; 4 | 5 | assert 200.add2.double.minus(2) == 402; 6 | -------------------------------------------------------------------------------- /test/while.mxc: -------------------------------------------------------------------------------- 1 | let a = 1; 2 | 3 | while 1 { 4 | if a >= 1000 { 5 | break; 6 | } 7 | a += a; 8 | } 9 | 10 | assert a == 1024; 11 | -------------------------------------------------------------------------------- /test/xortest.mxc: -------------------------------------------------------------------------------- 1 | def test(a: int, b: int): int { 2 | return a xor b; 3 | } 4 | --------------------------------------------------------------------------------