mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
update amalgamate.py
This commit is contained in:
parent
86675d7887
commit
71dca71ead
22
.github/workflows/main.yml
vendored
22
.github/workflows/main.yml
vendored
@ -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:
|
||||
|
175
amalgamate.py
175
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")
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PK_REGION(name) 1
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
|
||||
typedef struct ManagedHeap{
|
||||
c11_vector no_gc;
|
||||
|
@ -1,10 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdlib.h"
|
||||
#include "assert.h"
|
||||
#include "string.h"
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "pocketpy/common/memorypool.h"
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -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"
|
||||
|
@ -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 <assert.h>
|
||||
#include <ctype.h>
|
||||
|
@ -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 <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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) {
|
||||
|
@ -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) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
#include "math.h"
|
||||
#include <math.h>
|
||||
|
||||
// https://easings.net/
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
#include "pocketpy/common/config.h"
|
||||
#include "pocketpy/common/export.h"
|
||||
#include "pocketpy/pocketpy.h"
|
||||
|
||||
#include "pocketpy/common/utils.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "time.h"
|
||||
#include <time.h>
|
||||
|
||||
#define NANOS_PER_SEC 1000000000
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user