From 71dca71ead636d0f108a968cd8c438c722615dc0 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Tue, 20 Aug 2024 13:04:55 +0800 Subject: [PATCH] update `amalgamate.py` --- .github/workflows/main.yml | 22 ++-- amalgamate.py | 175 +++++++++++++++++---------- include/pocketpy/common/utils.h | 4 +- include/pocketpy/interpreter/frame.h | 1 - include/pocketpy/interpreter/heap.h | 1 - include/pocketpy/objects/base.h | 8 +- src/common/memorypool.c | 2 +- src/common/sstream.c | 1 - src/compiler/compiler.c | 1 - src/compiler/lexer.c | 35 +++--- src/interpreter/ceval.c | 2 +- src/modules/easing.c | 2 +- src/modules/os.c | 2 - src/modules/time.c | 2 +- 14 files changed, 148 insertions(+), 110 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 33a9c8f5..7312cc0d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,17 +12,17 @@ on: - 'web/**' - '**.md' jobs: - # build_win32_amalgamated: - # runs-on: windows-latest - # steps: - # - uses: actions/checkout@v4 - # - uses: ilammy/msvc-dev-cmd@v1 - # - name: Compile - # shell: powershell - # run: | - # python amalgamate.py - # cd amalgamated - # cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe + build_win32_amalgamated: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: ilammy/msvc-dev-cmd@v1 + - name: Compile + shell: powershell + run: | + python amalgamate.py + cd amalgamated + cl.exe /std:c11 /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.c /link /out:pkpy.exe build_win32: runs-on: windows-latest steps: diff --git a/amalgamate.py b/amalgamate.py index fd4054a3..9d96173d 100644 --- a/amalgamate.py +++ b/amalgamate.py @@ -7,36 +7,51 @@ from typing import List, Dict assert os.system("python prebuild.py") == 0 -with open("include/pocketpy/xmacros/opcodes.h", "rt", encoding='utf-8') as f: - OPCODES_TEXT = '\n' + f.read() + '\n' +ROOT = 'include/pocketpy' +PUBLIC_HEADERS = ['common/config.h', 'common/export.h', 'pocketpy.h'] + +COPYRIGHT = '''/* + * Copyright (c) 2024 blueloveTH + * Distributed Under The MIT License + * https://github.com/pocketpy/pocketpy + */ + ''' + +def read_file(path): + with open(path, 'rt', encoding='utf-8') as f: + return f.read() + +def write_file(path, content): + with open(path, 'wt', encoding='utf-8', newline='\n') as f: + f.write(content) + +if os.path.exists('amalgamated'): + shutil.rmtree('amalgamated') + time.sleep(0.5) + +os.mkdir('amalgamated') class Header: path: str - content: str # header+source (if exists) + content: str # header source dependencies: List[str] def __init__(self, path: str): self.path = path self.dependencies = [] - - # get raw content - with open(f'include/pocketpy/{path}', 'rt', encoding='utf-8') as f: - self.content = f.read() - src_path = path.replace('.hpp', '.cpp').replace('.h', '.cpp') - if os.path.exists(f'src/{src_path}'): - with open(f'src/{src_path}', 'rt', encoding='utf-8') as f: - self.content += f'\n\n/* {src_path} */\n\n' - self.content += f.read() + self.content = read_file(f'{ROOT}/{path}') # process raw content and get dependencies self.content = self.content.replace('#pragma once', '') def _replace(m): path = m.group(1) - if path == 'opcodes.h': - return OPCODES_TEXT + if path.startswith('xmacros/'): + return read_file(f'{ROOT}/{path}') + '\n' + if path in PUBLIC_HEADERS: + return '' # remove include if path != self.path: self.dependencies.append(path) - return '' + return '' # remove include self.content = re.sub( r'#include\s+"pocketpy/(.+)"\s*', @@ -46,69 +61,103 @@ class Header: def __repr__(self): return f'Header({self.path!r}, dependencies={self.dependencies})' + + def text(self): + return f'// {self.path}\n{self.content}\n' headers: Dict[str, Header] = {} -for path in ['pocketpy.hpp', 'pocketpy_c.h']: - headers[path] = Header(path) +for entry in os.listdir(ROOT): + if os.path.isdir(f'{ROOT}/{entry}'): + if entry == 'xmacros' or entry in PUBLIC_HEADERS: + continue + files = os.listdir(f'{ROOT}/{entry}') + for file in sorted(files): + assert file.endswith('.h') + if entry in PUBLIC_HEADERS: + continue + headers[f'{entry}/{file}'] = Header(f'{entry}/{file}') -directories = ['common', 'objects', 'interpreter', 'compiler', 'modules', 'tools'] -for directory in directories: - files = os.listdir(f'include/pocketpy/{directory}') - for file in sorted(files): - assert file.endswith('.h') or file.endswith('.hpp') - headers[f'{directory}/{file}'] = Header(f'{directory}/{file}') +def merge_c_files(): + c_files = [COPYRIGHT, '\n', '#include "pocketpy.h"', '\n'] -text = '''#pragma once - -/* - * Copyright (c) 2024 blueloveTH - * Distributed Under The MIT License - * https://github.com/pocketpy/pocketpy - */''' - -while True: - for h in headers.values(): - if not h.dependencies: + # merge internal headers + internal_h = [] + while True: + for h in headers.values(): + if not h.dependencies: + break + else: + if headers: + print(headers) + raise RuntimeError("Circular dependencies detected") break - else: - if headers: - print(headers) - raise Exception("Circular dependencies detected") - break - print(h.path) - text += h.content - del headers[h.path] - for h2 in headers.values(): - h2.dependencies = [d for d in h2.dependencies if d != h.path] + # print(h.path) + internal_h.append(h.text()) + del headers[h.path] + for h2 in headers.values(): + h2.dependencies = [d for d in h2.dependencies if d != h.path] -if os.path.exists("amalgamated"): - shutil.rmtree("amalgamated") - time.sleep(0.5) -os.mkdir("amalgamated") + c_files.extend(internal_h) -# use LF line endings instead of CRLF -with open("amalgamated/pocketpy.h", "wt", encoding='utf-8', newline='\n') as f: - f.write(text) + def _replace(m): + path = m.group(1) + if path.startswith('xmacros/'): + return read_file(f'{ROOT}/{path}') + '\n' + return '' # remove include -shutil.copy("src2/main.cpp", "amalgamated/main.cpp") -with open("amalgamated/main.cpp", "rt", encoding='utf-8') as f: - text = f.read() -text = text.replace('#include "pocketpy/pocketpy.h"', '#include "pocketpy.h"') -with open("amalgamated/main.cpp", "wt", encoding='utf-8', newline='\n') as f: - f.write(text) + for root, _, files in os.walk('src/'): + for file in files: + if file.endswith('.c'): + path = os.path.join(root, file) + c_files.append(f'// {path}\n') + content = read_file(path) + content = re.sub( + r'#include\s+"pocketpy/(.+)"\s*', + _replace, + content, + ) + c_files.append(content) + c_files.append('\n') + return ''.join(c_files) + +def merge_h_files(): + h_files = [COPYRIGHT, '#pragma once'] + + def _replace(m): + path = m.group(1) + if path.startswith('xmacros/'): + return read_file(f'{ROOT}/{path}') + '\n' + return '' # remove include + + for path in PUBLIC_HEADERS: + content = read_file(f'{ROOT}/{path}') + content = content.replace('#pragma once', '') + content = re.sub( + r'#include\s+"pocketpy/(.+)"\s*', + _replace, + content, + ) + h_files.append(content) + return '\n'.join(h_files) + + +write_file('amalgamated/pocketpy.c', merge_c_files()) +write_file('amalgamated/pocketpy.h', merge_h_files()) + +shutil.copy("src2/main.c", "amalgamated/main.c") if sys.platform in ['linux', 'darwin']: - ok = os.system("clang++ -o main amalgamated/main.cpp -O1 --std=c++17 -frtti -stdlib=libc++") + ok = os.system("clang -o main amalgamated/pocketpy.c amalgamated/main.c -O1 --std=c11 -lm") if ok == 0: print("Test build success!") print("amalgamated/pocketpy.h") -def sync(path): - shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h")) - with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8', newline='\n') as f: - f.write("#include \"pocketpy.h\"\n") +# def sync(path): +# shutil.copy("amalgamated/pocketpy.h", os.path.join(path, "pocketpy.h")) +# with open(os.path.join(path, "pocketpy.cpp"), "wt", encoding='utf-8', newline='\n') as f: +# f.write("#include \"pocketpy.h\"\n") -sync("plugins/macos/pocketpy") +# sync("plugins/macos/pocketpy") diff --git a/include/pocketpy/common/utils.h b/include/pocketpy/common/utils.h index 39f58436..0eed3634 100644 --- a/include/pocketpy/common/utils.h +++ b/include/pocketpy/common/utils.h @@ -1,7 +1,7 @@ #pragma once -#include "stdio.h" -#include "stdlib.h" +#include +#include #define PK_REGION(name) 1 diff --git a/include/pocketpy/interpreter/frame.h b/include/pocketpy/interpreter/frame.h index 753949cd..76a01001 100644 --- a/include/pocketpy/interpreter/frame.h +++ b/include/pocketpy/interpreter/frame.h @@ -4,7 +4,6 @@ #include "pocketpy/objects/codeobject.h" #include "pocketpy/objects/namedict.h" #include "pocketpy/objects/object.h" -#include "pocketpy/common/config.h" #include "pocketpy/common/strname.h" #include "pocketpy/pocketpy.h" diff --git a/include/pocketpy/interpreter/heap.h b/include/pocketpy/interpreter/heap.h index 1f665ae6..5fd2b59c 100644 --- a/include/pocketpy/interpreter/heap.h +++ b/include/pocketpy/interpreter/heap.h @@ -1,5 +1,4 @@ #include "pocketpy/objects/object.h" -#include "pocketpy/common/config.h" typedef struct ManagedHeap{ c11_vector no_gc; diff --git a/include/pocketpy/objects/base.h b/include/pocketpy/objects/base.h index d1ac55b5..28508a2c 100644 --- a/include/pocketpy/objects/base.h +++ b/include/pocketpy/objects/base.h @@ -1,10 +1,8 @@ #pragma once -#include "stdint.h" -#include "stdbool.h" -#include "stdlib.h" -#include "assert.h" -#include "string.h" +#include +#include +#include #include "pocketpy/common/utils.h" #include "pocketpy/pocketpy.h" diff --git a/src/common/memorypool.c b/src/common/memorypool.c index 34c19a7c..bd3adc8c 100644 --- a/src/common/memorypool.c +++ b/src/common/memorypool.c @@ -1,5 +1,5 @@ #include "pocketpy/common/memorypool.h" -#include "pocketpy/common/config.h" +#include "pocketpy/pocketpy.h" #include #include diff --git a/src/common/sstream.c b/src/common/sstream.c index 0e19bf24..10ceba9a 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -1,5 +1,4 @@ #include "pocketpy/common/sstream.h" -#include "pocketpy/common/config.h" #include "pocketpy/common/str.h" #include "pocketpy/common/utils.h" #include "pocketpy/pocketpy.h" diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index ad3d09f2..3fd4c9cb 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -5,7 +5,6 @@ #include "pocketpy/objects/object.h" #include "pocketpy/common/strname.h" #include "pocketpy/common/sstream.h" -#include "pocketpy/common/config.h" #include "pocketpy/common/memorypool.h" #include #include diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 42c0502d..884efbeb 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -1,12 +1,9 @@ #include "pocketpy/common/smallmap.h" -#include "pocketpy/common/config.h" #include "pocketpy/common/sstream.h" #include "pocketpy/common/vector.h" #include "pocketpy/compiler/lexer.h" #include "pocketpy/objects/sourcedata.h" #include -#include -#include #define is_raw_string_used(t) ((t) == TK_ID) @@ -201,7 +198,7 @@ static bool is_possible_number_char(char c) { } /******************************/ -static Error* SyntaxError(Lexer* self, const char* fmt, ...) { +static Error* LexerError(Lexer* self, const char* fmt, ...) { Error* err = malloc(sizeof(Error)); err->src = self->src; PK_INCREF(self->src); @@ -219,7 +216,7 @@ static Error* eat_name(Lexer* self) { while(true) { unsigned char c = *self->curr_char; int u8bytes = c11__u8_header(c, true); - if(u8bytes == 0) return SyntaxError(self, "invalid char: %c", c); + if(u8bytes == 0) return LexerError(self, "invalid char: %c", c); if(u8bytes == 1) { if(isalnum(c) || c == '_') { self->curr_char++; @@ -251,7 +248,7 @@ static Error* eat_name(Lexer* self) { } int length = (int)(self->curr_char - self->token_start); - if(length == 0) return SyntaxError(self, "@id contains invalid char"); + if(length == 0) return LexerError(self, "@id contains invalid char"); c11_sv name = {self->token_start, length}; const char** KW_BEGIN = TokenSymbols + TK_FALSE; @@ -289,10 +286,10 @@ static Error* _eat_string(Lexer* self, c11_sbuf* buff, char quote, enum StringTy // end of string break; } - if(c == '\0') { return SyntaxError(self, "EOL while scanning string literal"); } + if(c == '\0') { return LexerError(self, "EOL while scanning string literal"); } if(c == '\n') { if(!quote3) - return SyntaxError(self, "EOL while scanning string literal"); + return LexerError(self, "EOL while scanning string literal"); else { c11_sbuf__write_char(buff, c); continue; @@ -311,11 +308,11 @@ static Error* _eat_string(Lexer* self, c11_sbuf* buff, char quote, enum StringTy char hex[3] = {eatchar(self), eatchar(self), '\0'}; int code; if(sscanf(hex, "%x", &code) != 1) { - return SyntaxError(self, "invalid hex char"); + return LexerError(self, "invalid hex char"); } c11_sbuf__write_char(buff, (char)code); } break; - default: return SyntaxError(self, "invalid escape char"); + default: return LexerError(self, "invalid escape char"); } } else { if(is_fstring) { @@ -343,7 +340,7 @@ static Error* _eat_string(Lexer* self, c11_sbuf* buff, char quote, enum StringTy } if(self->nexts.length == token_count) { // f'{}' is not allowed - return SyntaxError(self, "f-string: empty expression not allowed"); + return LexerError(self, "f-string: empty expression not allowed"); } } } else if(c == '}') { @@ -351,7 +348,7 @@ static Error* _eat_string(Lexer* self, c11_sbuf* buff, char quote, enum StringTy // '}}' -> '}' c11_sbuf__write_char(buff, '}'); } else { - return SyntaxError(self, "f-string: single '}' is not allowed"); + return LexerError(self, "f-string: single '}' is not allowed"); } } else { c11_sbuf__write_char(buff, c); @@ -412,7 +409,7 @@ static Error* eat_number(Lexer* self) { TokenValue value = {.index = TokenValue_I64}; switch(c11__parse_uint(text, &value._i64, -1)) { case IntParsing_SUCCESS: add_token_with_value(self, TK_NUM, value); return NULL; - case IntParsing_OVERFLOW: return SyntaxError(self, "int literal is too large"); + case IntParsing_OVERFLOW: return LexerError(self, "int literal is too large"); case IntParsing_FAILURE: break; // do nothing } } @@ -434,14 +431,14 @@ static Error* eat_number(Lexer* self) { return NULL; } - return SyntaxError(self, "invalid number literal"); + return LexerError(self, "invalid number literal"); } static Error* eat_fstring_spec(Lexer* self, bool* eof) { while(true) { char c = eatchar_include_newline(self); if(c == '\n' || c == '\0') { - return SyntaxError(self, "EOL while scanning f-string format spec"); + return LexerError(self, "EOL while scanning f-string format spec"); } if(c == '}') { add_token(self, TK_FSTR_SPEC); @@ -491,7 +488,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) { // line continuation character char c = eatchar_include_newline(self); if(c != '\n') { - return SyntaxError(self, "expected newline after line continuation character"); + return LexerError(self, "expected newline after line continuation character"); } eat_spaces(self); return NULL; @@ -555,7 +552,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) { add_token(self, TK_NE); return NULL; } else { - return SyntaxError(self, "expected '=' after '!'"); + return LexerError(self, "expected '=' after '!'"); } case '*': if(matchchar(self, '*')) { @@ -576,7 +573,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) { case '\n': { add_token(self, TK_EOL); if(!eat_indentation(self)) { - return SyntaxError(self, "unindent does not match any outer indentation level"); + return LexerError(self, "unindent does not match any outer indentation level"); } return NULL; } @@ -597,7 +594,7 @@ static Error* lex_one_token(Lexer* self, bool* eof, bool is_fstring) { } } - if(is_fstring) return SyntaxError(self, "unterminated f-string expression"); + if(is_fstring) return LexerError(self, "unterminated f-string expression"); self->token_start = self->curr_char; while(self->indents.length > 1) { diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index cf8591b6..a73dae16 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -1,4 +1,3 @@ -#include "pocketpy/common/config.h" #include "pocketpy/common/str.h" #include "pocketpy/common/utils.h" #include "pocketpy/interpreter/frame.h" @@ -90,6 +89,7 @@ FrameResult VM__run_top_frame(VM* self) { #if PK_DEBUG pk_print_stack(self, frame, byte); + // assert(!py_checkexc(true)); #endif switch((Opcode)byte.op) { diff --git a/src/modules/easing.c b/src/modules/easing.c index 8660161b..de49ec7a 100644 --- a/src/modules/easing.c +++ b/src/modules/easing.c @@ -1,7 +1,7 @@ #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/vm.h" -#include "math.h" +#include // https://easings.net/ diff --git a/src/modules/os.c b/src/modules/os.c index 7bbf052a..d530ae35 100644 --- a/src/modules/os.c +++ b/src/modules/os.c @@ -1,5 +1,3 @@ -#include "pocketpy/common/config.h" -#include "pocketpy/common/export.h" #include "pocketpy/pocketpy.h" #include "pocketpy/common/utils.h" diff --git a/src/modules/time.c b/src/modules/time.c index de21067f..e453e5a4 100644 --- a/src/modules/time.c +++ b/src/modules/time.c @@ -1,6 +1,6 @@ #include "pocketpy/pocketpy.h" #include "pocketpy/interpreter/vm.h" -#include "time.h" +#include #define NANOS_PER_SEC 1000000000