Jelajahi Sumber

add `csv` module

blueloveTH 2 tahun lalu
induk
melakukan
a62943568f
7 mengubah file dengan 130 tambahan dan 1 penghapusan
  1. 1 1
      amalgamate.py
  2. 25 0
      docs/modules/csv.md
  3. 9 0
      include/pocketpy/csv.h
  4. 1 0
      include/pocketpy/pocketpy.h
  5. 56 0
      src/csv.cpp
  6. 10 0
      src/pocketpy.cpp
  7. 28 0
      tests/80_csv.py

+ 1 - 1
amalgamate.py

@@ -9,7 +9,7 @@ pipeline = [
 	["config.h", "export.h", "common.h", "memory.h", "vector.h", "str.h", "tuplelist.h", "namedict.h", "error.h", "lexer.h"],
 	["obj.h", "dict.h", "codeobject.h", "frame.h"],
 	["gc.h", "vm.h", "ceval.h", "expr.h", "compiler.h", "repl.h"],
-	["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "collections.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
+	["_generated.h", "cffi.h", "bindings.h", "iter.h", "base64.h", "csv.h", "collections.h", "random.h", "re.h", "linalg.h", "easing.h", "io.h"],
 	["pocketpy.h", "pocketpy_c.h"]
 ]
 

+ 25 - 0
docs/modules/csv.md

@@ -0,0 +1,25 @@
+---
+icon: package
+label: csv
+---
+
+### `csv.reader(csvfile: list[str]) -> list`
+
+Parse a CSV file into a list of lists.
+
+
+## Example
+
+```python
+import csv
+
+data = """a,b,c
+1,2,3
+"""
+
+print(csv.reader(data.splitlines()))
+# [
+#    ['a', 'b', 'c'],
+#    ['1', '2', '3']
+# ]
+```

+ 9 - 0
include/pocketpy/csv.h

@@ -0,0 +1,9 @@
+#pragma once
+
+#include "cffi.h"
+
+namespace pkpy {
+
+void add_module_csv(VM* vm);
+
+} // namespace pkpy

+ 1 - 0
include/pocketpy/pocketpy.h

@@ -14,6 +14,7 @@
 #include "random.h"
 #include "bindings.h"
 #include "collections.h"
+#include "csv.h"
 
 namespace pkpy {
 

+ 56 - 0
src/csv.cpp

@@ -0,0 +1,56 @@
+#include "pocketpy/csv.h"
+#include "pocketpy/config.h"
+
+namespace pkpy{
+
+void add_module_csv(VM *vm){
+    PyObject* mod = vm->new_module("csv");
+
+    vm->bind(mod, "reader(csvfile: list[str]) -> list", [](VM* vm, ArgsView args){
+        const List& csvfile = CAST(List&, args[0]);
+        List ret;
+        for(int i=0; i<csvfile.size(); i++){
+            std::string_view line = CAST(Str&, csvfile[i]).sv();
+            List row;
+            int j = 0;
+            bool in_quote = false;
+            std::string buffer;
+            while(j < line.size()){
+                switch(line[j]){
+                    case '"':
+                        if(in_quote){
+                            if(j+1 < line.size() && line[j+1] == '"'){
+                                buffer += '"';
+                                j++;
+                            }else{
+                                in_quote = false;
+                            }
+                        }else{
+                            in_quote = true;
+                        }
+                        break;
+                    case ',':
+                        if(in_quote){
+                            buffer += line[j];
+                        }else{
+                            row.push_back(VAR(buffer));
+                            buffer.clear();
+                        }
+                        break;
+                    default:
+                        buffer += line[j];
+                        break;
+                }
+                j++;
+            }
+            if(in_quote){
+                vm->ValueError("unterminated quote");
+            }
+            row.push_back(VAR(buffer));
+            ret.push_back(VAR(std::move(row)));
+        }
+        return VAR(std::move(ret));
+    });
+}
+
+}   // namespace pkpy

+ 10 - 0
src/pocketpy.cpp

@@ -549,6 +549,15 @@ void init_builtins(VM* _vm) {
         return VAR(std::move(ret));
     });
 
+    _vm->bind(_vm->_t(_vm->tp_str), "splitlines(self)", [](VM* vm, ArgsView args) {
+        const Str& self = _CAST(Str&, args[0]);
+        std::vector<std::string_view> parts;
+        parts = self.split('\n');
+        List ret(parts.size());
+        for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
+        return VAR(std::move(ret));
+    });
+
     _vm->bind(_vm->_t(_vm->tp_str), "count(self, s: str)", [](VM* vm, ArgsView args) {
         const Str& self = _CAST(Str&, args[0]);
         const Str& s = CAST(Str&, args[1]);
@@ -1646,6 +1655,7 @@ void VM::post_init(){
     add_module_base64(this);
     add_module_timeit(this);
     add_module_operator(this);
+    add_module_csv(this);
 
     for(const char* name: {"this", "functools", "heapq", "bisect", "pickle", "_long", "colorsys", "typing", "datetime"}){
         _lazy_modules[name] = kPythonLibs[name];

+ 28 - 0
tests/80_csv.py

@@ -0,0 +1,28 @@
+import csv
+def test(data: str, expected):
+    ret = list(csv.reader(data.splitlines()))
+    assert ret==expected, f"Expected {expected}, got {ret}"
+
+test("""a,b,c
+1,2,3
+""",  [['a', 'b', 'c'], ['1', '2', '3']])
+
+test("""a,b,c
+1,2,"3"
+""",  [['a', 'b', 'c'], ['1', '2', '3']])
+
+test("""a,b,c
+1,2,'3'
+""",  [['a', 'b', 'c'], ['1', '2', '\'3\'']])
+
+test('''a,b,c
+1,2,"123"""
+''',  [['a', 'b', 'c'], ['1', '2', '123"']])
+
+test("""a,b,c,
+1,2,3,
+""",  [['a', 'b', 'c', ''], ['1', '2', '3', '']])
+
+test("""a,b ,c,
+1,"22""33",3
+""",  [['a', 'b ', 'c', ''], ['1', '22"33', '3']])