blueloveTH 1 год назад
Родитель
Сommit
79012a6b08
5 измененных файлов с 190 добавлено и 114 удалено
  1. 4 8
      include/pocketpy/pocketpy.h
  2. 130 4
      src/compiler/compiler.c
  3. 6 0
      src/public/modules.c
  4. 9 4
      src/public/py_str.c
  5. 41 98
      tests/04_str.py

+ 4 - 8
include/pocketpy/pocketpy.h

@@ -38,13 +38,7 @@ enum BindType {
     BindType_CLASSMETHOD,
 };
 
-enum CompileMode {
-    EXEC_MODE,
-    EVAL_MODE,
-    REPL_MODE,
-    JSON_MODE,
-    CELL_MODE
-};
+enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
 
 /************* Global VMs *************/
 void py_initialize();
@@ -294,7 +288,9 @@ bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv);
 bool py_callmagic(py_Name name, int argc, py_Ref argv);
 
 bool py_str(py_Ref val);
-bool py_repr(py_Ref val);
+
+#define py_repr(val) py_callmagic(__repr__, 1, val)
+#define py_len(val) py_callmagic(__len__, 1, val)
 
 /// The return value of the most recent call.
 py_GlobalRef py_retval();

+ 130 - 4
src/compiler/compiler.c

@@ -4,6 +4,7 @@
 #include "pocketpy/objects/sourcedata.h"
 #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 <ctype.h>
@@ -2348,6 +2349,124 @@ static Error* compile_function(Compiler* self, int decorators) {
     return NULL;
 }
 
+static Error* compile_decorated(Compiler* self) {
+    Error* err;
+    int count = 0;
+    do {
+        check(EXPR(self));
+        count += 1;
+        if(!match_newlines()) return SyntaxError("expected a newline after '@'");
+    } while(match(TK_DECORATOR));
+
+    if(match(TK_CLASS)) {
+        // check(compile_class(count));
+    } else {
+        consume(TK_DEF);
+        check(compile_function(self, count));
+    }
+    return NULL;
+}
+
+// import a [as b]
+// import a [as b], c [as d]
+static Error* compile_normal_import(Compiler* self) {
+    do {
+        consume(TK_ID);
+        c11_sv name = Token__sv(prev());
+        int index = Ctx__add_const_string(ctx(), name);
+        Ctx__emit_(ctx(), OP_IMPORT_PATH, index, prev()->line);
+        if(match(TK_AS)) {
+            consume(TK_ID);
+            name = Token__sv(prev());
+        }
+        Ctx__emit_store_name(ctx(), name_scope(self), py_name2(name), prev()->line);
+    } while(match(TK_COMMA));
+    consume_end_stmt();
+    return NULL;
+}
+
+// from a import b [as c], d [as e]
+// from a.b import c [as d]
+// from . import a [as b]
+// from .a import b [as c]
+// from ..a import b [as c]
+// from .a.b import c [as d]
+// from xxx import *
+static Error* compile_from_import(c11_sbuf* buf, Compiler* self) {
+    int dots = 0;
+
+    while(true) {
+        switch(curr()->type) {
+            case TK_DOT: dots += 1; break;
+            case TK_DOTDOT: dots += 2; break;
+            case TK_DOTDOTDOT: dots += 3; break;
+            default: goto __EAT_DOTS_END;
+        }
+        advance();
+    }
+__EAT_DOTS_END:
+    for(int i = 0; i < dots; i++) {
+        c11_sbuf__write_char(buf, '.');
+    }
+
+    if(dots > 0) {
+        // @id is optional if dots > 0
+        if(match(TK_ID)) {
+            c11_sbuf__write_sv(buf, Token__sv(prev()));
+            while(match(TK_DOT)) {
+                consume(TK_ID);
+                c11_sbuf__write_char(buf, '.');
+                c11_sbuf__write_sv(buf, Token__sv(prev()));
+            }
+        }
+    } else {
+        // @id is required if dots == 0
+        consume(TK_ID);
+        c11_sbuf__write_sv(buf, Token__sv(prev()));
+        while(match(TK_DOT)) {
+            consume(TK_ID);
+            c11_sbuf__write_char(buf, '.');
+            c11_sbuf__write_sv(buf, Token__sv(prev()));
+        }
+    }
+
+    c11_string* path = c11_sbuf__submit(buf);
+    Ctx__emit_(ctx(),
+               OP_IMPORT_PATH,
+               Ctx__add_const_string(ctx(), c11_string__sv(path)),
+               prev()->line);
+    consume(TK_IMPORT);
+
+    if(match(TK_MUL)) {
+        if(name_scope(self) != NAME_GLOBAL)
+            return SyntaxError("from <module> import * can only be used in global scope");
+        // pop the module and import __all__
+        Ctx__emit_(ctx(), OP_POP_IMPORT_STAR, BC_NOARG, prev()->line);
+        consume_end_stmt();
+        return NULL;
+    }
+
+    do {
+        Ctx__emit_(ctx(), OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
+        consume(TK_ID);
+        c11_sv name = Token__sv(prev());
+        Ctx__emit_(ctx(), OP_LOAD_ATTR, py_name2(name), prev()->line);
+        if(match(TK_AS)) {
+            consume(TK_ID);
+            name = Token__sv(prev());
+        }
+        Ctx__emit_store_name(ctx(), name_scope(self), py_name2(name), prev()->line);
+    } while(match(TK_COMMA));
+    Ctx__emit_(ctx(), OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
+    consume_end_stmt();
+    return NULL;
+}
+
+static Error* compile_try_except(Compiler* self) {
+    assert(false);
+    return NULL;
+}
+
 static Error* compile_stmt(Compiler* self) {
     Error* err;
     if(match(TK_CLASS)) {
@@ -2402,11 +2521,18 @@ static Error* compile_stmt(Compiler* self) {
         case TK_IF: check(compile_if_stmt(self)); break;
         case TK_WHILE: check(compile_while_loop(self)); break;
         case TK_FOR: check(compile_for_loop(self)); break;
-        // case TK_IMPORT: check(compile_normal_import()); break;
-        // case TK_FROM: check(compile_from_import()); break;
+        case TK_IMPORT: check(compile_normal_import(self)); break;
+        case TK_FROM: {
+            c11_sbuf buf;
+            c11_sbuf__ctor(&buf);
+            err = compile_from_import(&buf, self);
+            c11_sbuf__dtor(&buf);
+            if(err) return err;
+            break;
+        }
         case TK_DEF: check(compile_function(self, 0)); break;
-        // case TK_DECORATOR: check(compile_decorated()); break;
-        // case TK_TRY: check(compile_try_except()); break;
+        case TK_DECORATOR: check(compile_decorated(self)); break;
+        case TK_TRY: check(compile_try_except(self)); break;
         case TK_PASS: consume_end_stmt(); break;
         /*************************************************/
         case TK_ASSERT: {

+ 6 - 0
src/public/modules.c

@@ -70,10 +70,16 @@ static bool _py_builtins__exit(int argc, py_Ref argv) {
     return false;
 }
 
+static bool _py_builtins__len(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    return py_len(argv);
+}
+
 py_TValue pk_builtins__register() {
     py_Ref builtins = py_newmodule("builtins", NULL);
     py_bindnativefunc(builtins, "repr", _py_builtins__repr);
     py_bindnativefunc(builtins, "exit", _py_builtins__exit);
+    py_bindnativefunc(builtins, "len", _py_builtins__len);
     return *builtins;
 }
 

+ 9 - 4
src/public/py_str.c

@@ -145,8 +145,15 @@ static bool _py_str__str__(int argc, py_Ref argv) {
 
 static bool _py_str__repr__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
-    assert(false);
-    return false;
+    c11_sbuf buf;
+    c11_sbuf__ctor(&buf);
+    int size;
+    const char* data = py_tostrn(&argv[0], &size);
+    c11_sbuf__write_quoted(&buf, (c11_sv){data, size}, '\'');
+    c11_string* res = c11_sbuf__submit(&buf);
+    py_newstrn(py_retval(), res->data, res->size);
+    c11_string__delete(res);
+    return true;
 }
 
 static bool _py_str__iter__(int argc, py_Ref argv) {
@@ -294,5 +301,3 @@ bool py_str(py_Ref val) {
     if(!tmp) return py_repr(val);
     return py_call(tmp, 1, val);
 }
-
-bool py_repr(py_Ref val) { return py_callmagic(__repr__, 1, val); }

+ 41 - 98
tests/04_str.py

@@ -44,7 +44,6 @@ assert s.replace("foo","ball") == "balltball"
 assert s.startswith('f') == True;assert s.endswith('o') == False
 assert t.startswith('this') == True;
 
-
 assert t.split('w') == ['this is string example....', 'o', '!!!']
 assert "a,b,c".split(',') == ['a', 'b', 'c']
 assert 'a,'.split(',') == ['a']
@@ -110,29 +109,9 @@ num = 6
 assert str(num) == '6'
 
 # test Lo group names
-
 测试 = "test"
 assert 测试 == "test"
 
-assert "Hello, {}!".format("World") == "Hello, World!"
-assert "{} {} {}".format("I", "love", "Python") == "I love Python"
-assert "{0} {1} {2}".format("I", "love", "Python") == "I love Python"
-assert "{2} {1} {0}".format("I", "love", "Python") == "Python love I"
-assert "{0}{1}{0}".format("abra", "cad") == "abracadabra"
-
-assert "{k}={v}".format(k="key", v="value") == "key=value"
-assert "{k}={k}".format(k="key") == "key=key"
-assert "{0}={1}".format('{0}', '{1}') == "{0}={1}"
-assert "{{{0}}}".format(1) == "{1}"
-assert "{0}{1}{1}".format(1, 2, 3) == "122"
-try:
-    "{0}={1}}".format(1, 2)
-    exit(1)
-except ValueError:
-    pass
-assert "{{{}xxx{}x}}".format(1, 2) == "{1xxx2x}"
-assert "{{abc}}".format() == "{abc}"
-
 # 3rd slice
 a = "Hello, World!"
 assert a[::-1] == "!dlroW ,olleH"
@@ -152,44 +131,13 @@ assert b[5:2:-2] == [',', 'l']
 a = '123'
 assert a.rjust(5) == '  123'
 assert a.rjust(5, '0') == '00123'
-try:
-    a.rjust(5, '00')
-    exit(1)
-except TypeError:
-    pass
 assert a.ljust(5) == '123  '
 assert a.ljust(5, '0') == '12300'
-try:
-    a.ljust(5, '00')
-    exit(1)
-except TypeError:
-    pass
 
 assert '\x30\x31\x32' == '012'
-
-a = 'abcd'
-assert list(a) == ['a', 'b', 'c', 'd']
-a = '测试'
-assert list(a) == ['测', '试']
-a = 'a测b试c'
-assert list(a) == ['a', '测', 'b', '试', 'c']
-a = 'a测b试'
-assert list(a) == ['a', '测', 'b', '试']
-a = '测b试c'
-assert list(a) == ['测', 'b', '试', 'c']
-a = '测b'
-assert list(a) == ['测', 'b']
-a = 'b'
-assert list(a) == ['b']
-a = '测'
-assert list(a) == ['测']
-
 assert '\b\b\b' == '\x08\x08\x08'
-stack=[1,2,3,4]; assert f"{stack[2:]}" == '[3, 4]'
-
 assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
 
-
 assert hex(-42) == '-0x2a'
 assert hex(42) == '0x2a'
 
@@ -202,35 +150,6 @@ assert hex(256) == '0x100'
 assert hex(257) == '0x101'
 assert hex(17) == '0x11'
 
-import c
-assert repr(c.NULL) == '<void* at 0x0>'
-assert repr(c.void_p(1)) == '<void* at 0x1>'
-assert repr(c.void_p(15)) == '<void* at 0xf>'
-assert repr(c.void_p(16)) == '<void* at 0x10>'
-assert repr(c.void_p(255)) == '<void* at 0xff>'
-assert repr(c.void_p(256)) == '<void* at 0x100>'
-assert repr(c.void_p(257)) == '<void* at 0x101>'
-assert repr(c.void_p(17)) == '<void* at 0x11>'
-
-# random hex test
-import random
-
-
-def test(__min, __max):
-    for _ in range(100):
-        num = random.randint(__min, __max)
-        hex_num = hex(num)
-        assert eval(hex_num) == num
-        if num >= 0:
-            assert repr(c.void_p(num)) == f'<void* at 0x{hex_num[2:]}>'
-
-test(0, 100)
-test(0, 100000)
-test(-100, 100)
-test(-100000, 100000)
-test(-2**30, 2**30)
-
-
 a = '123'
 assert a.index('2') == 1
 assert a.index('1') == 0
@@ -239,23 +158,47 @@ assert a.index('3') == 2
 assert a.index('2', 1) == 1
 assert a.index('1', 0) == 0
 
-try:
-    a.index('1', 1)
-    exit(1)
-except ValueError:
-    pass
-
-try:
-    a.index('1', -1)
-    exit(1)
-except ValueError:
-    pass
-
 assert a.find('1') == 0
 assert a.find('1', 1) == -1
 
-try:
-    a.find('1', -1)
-    exit(1)
-except ValueError:
-    pass
+a = 'abcd'
+assert list(a) == ['a', 'b', 'c', 'd']
+a = '测试'
+assert list(a) == ['测', '试']
+a = 'a测b试c'
+assert list(a) == ['a', '测', 'b', '试', 'c']
+a = 'a测b试'
+assert list(a) == ['a', '测', 'b', '试']
+a = '测b试c'
+assert list(a) == ['测', 'b', '试', 'c']
+a = '测b'
+assert list(a) == ['测', 'b']
+a = 'b'
+assert list(a) == ['b']
+a = '测'
+assert list(a) == ['测']
+
+# test format()
+assert "Hello, {}!".format("World") == "Hello, World!"
+assert "{} {} {}".format("I", "love", "Python") == "I love Python"
+assert "{0} {1} {2}".format("I", "love", "Python") == "I love Python"
+assert "{2} {1} {0}".format("I", "love", "Python") == "Python love I"
+assert "{0}{1}{0}".format("abra", "cad") == "abracadabra"
+
+assert "{k}={v}".format(k="key", v="value") == "key=value"
+assert "{k}={k}".format(k="key") == "key=key"
+assert "{0}={1}".format('{0}', '{1}') == "{0}={1}"
+assert "{{{0}}}".format(1) == "{1}"
+assert "{0}{1}{1}".format(1, 2, 3) == "122"
+
+# try:
+#     "{0}={1}}".format(1, 2)
+#     exit(1)
+# except ValueError:
+#     pass
+
+assert "{{{}xxx{}x}}".format(1, 2) == "{1xxx2x}"
+assert "{{abc}}".format() == "{abc}"
+
+# test f-string
+stack=[1,2,3,4]; assert f"{stack[2:]}" == '[3, 4]'