add compiler-rust as normal file

This commit is contained in:
lyon 2021-09-05 14:35:46 +08:00
parent 7e0b3b279f
commit 460733d914
23 changed files with 1415 additions and 0 deletions

2
pikascript-compiler-rust/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/pikascript-api

View File

@ -0,0 +1,27 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/target/debug/rust-msc",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

View File

@ -0,0 +1,11 @@
from PikaObj import *
class Line(TinyObj):
def new():
pass
def delete():
pass
def moveTo(x: int, y: int):
pass

7
pikascript-compiler-rust/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "rust-msc"
version = "0.1.0"

View File

@ -0,0 +1,7 @@
[package]
name = "rust-msc"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,14 @@
class TinyObj:
pass
class BaseObj(TinyObj):
pass
def print(val: any):
pass
def set(argPath: str, val: any):
pass

View File

@ -0,0 +1,27 @@
from PikaObj import *
class MemChecker(BaseObj):
def max():
pass
def now():
pass
def resetMax():
pass
class SysObj(BaseObj):
def type(argPath: str):
pass
def ls(objPath: str):
pass
def remove(argPath: str):
pass
def new(objPath: str, classPath: str):
pass

View File

@ -0,0 +1,39 @@
class PyObj(BaseObj):
def importClass(className: str, fp: str):
pass
def newObj(objName: str, className: str, fp: str):
pass
def makeInlcude(fp: str):
pass
def makeNewObj(fp: str):
pass
def getInclude() -> str:
pass
class PyMethod (SysObj):
def makeMethodFun(fp: str):
pass
def makeMethodDeclear(fp: str):
pass
def makeMethodDefine(fp: str):
pass
class PyClass(SysObj):
obj = PyObj()
PyMethod()
def setSuper(superClassName: str):
pass
def makeApi(path: str):
pass
def makeHead(path: str):
pass

View File

@ -0,0 +1,2 @@
# pikascript-compiler-rust

View File

@ -0,0 +1,22 @@
import PyInfo
import Arm2D
import PikaStdLib
from PikaObj import *
class Compiler(PikaStdLib.SysObj):
obj = PyInfo.PyObj()
PyInfo.PyMethod()
PyInfo.PyClass()
line = Arm2D.Line()
def build(pythonApiPath: str, outputPath: str) -> int:
pass
def analyzestr(pythonApiPath: str) -> int:
pass
def analyzeLine(line: str) -> int:
pass
class MyRoot(PikaStdLib.SysObj):
compiler = Compiler()

View File

@ -0,0 +1,2 @@
rm pikascript-api -rf
mkdir pikascript-api

View File

@ -0,0 +1,7 @@
import Arm2D
import PyInfo
line = Arm2D.Line()
res = line.on()
line.off()
line.moveTo(20)

View File

@ -0,0 +1,96 @@
use crate::my_string;
use crate::py_arg::PyArg;
use std::collections::BTreeMap;
#[derive(Debug)]
pub struct ArgList {
py_arg_list: String,
list: BTreeMap<String, PyArg>,
}
impl ArgList {
pub fn to_string(&self) -> String {
return self.py_arg_list.clone();
}
pub fn new(py_arg_list: &Option<String>) -> Option<ArgList> {
let py_arg_list = match py_arg_list {
Some(x) => x,
None => return None,
};
let mut arg_list = ArgList {
py_arg_list: py_arg_list.clone(),
list: BTreeMap::new(),
};
let py_arg_list = py_arg_list.replace(" ", "");
let py_arg_list: Vec<&str> = py_arg_list.split(",").collect();
for arg_define in py_arg_list.iter() {
let arg_name = match my_string::get_first_token(&arg_define.to_string(), ':') {
Some(name) => name,
None => return None,
};
let type_name = match my_string::get_last_token(&arg_define.to_string(), ':') {
Some(name) => name,
None => return None,
};
arg_list
.list
.entry(arg_name.clone())
.or_insert(PyArg::new(&arg_name, &type_name));
}
return Some(arg_list);
}
pub fn to_c(&self) -> String {
let mut arg_list_in_c = String::from("");
for (i, (_, py_arg)) in self.list.iter().enumerate() {
let arg_name = py_arg.name();
let type_name_in_c = py_arg.c_type();
arg_list_in_c.push_str(&type_name_in_c);
arg_list_in_c.push_str(" ");
arg_list_in_c.push_str(&arg_name);
if i < self.list.len() - 1 {
arg_list_in_c.push_str(", ");
}
}
return arg_list_in_c;
}
pub fn call_arg_list(&self) -> String {
let mut call_arg_list = "".to_string();
for (i, (_, py_arg)) in self.list.iter().enumerate() {
let arg_name = py_arg.name();
call_arg_list.push_str(&arg_name);
if i < self.list.len() - 1 {
call_arg_list.push_str(", ");
}
}
return call_arg_list;
}
pub fn get_local_args(&self) -> String {
let mut get_local_args = "".to_string();
for (_, py_arg) in self.list.iter() {
get_local_args.push_str(&py_arg.get_local_arg());
}
return get_local_args;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arg_list() {
let arg_list =
ArgList::new(&Some(String::from("arg1: str, arg2: int, arg3: FILE"))).unwrap();
let arg_list_in_c = arg_list.to_c();
let call_arg_list = arg_list.call_arg_list();
let get_local_args = arg_list.get_local_args();
assert_eq! {arg_list_in_c,"char * arg1, int arg2, void * arg3"};
assert_eq! {call_arg_list,"arg1, arg2, arg3"};
assert_eq! {get_local_args," char * arg1 = args_getStr(args, \"arg1\");\n int arg2 = args_getInt(args, \"arg2\");\n void * arg3 = args_getPtr(args, \"arg3\");\n"};
}
#[test]
fn test_arg_list_one_arg() {
let arg_list = ArgList::new(&Some(String::from("argtest: str"))).unwrap();
let arg_list_in_c = arg_list.to_c();
assert_eq! {arg_list_in_c,"char * argtest"};
}
}

View File

@ -0,0 +1,272 @@
use crate::import_info::ImportInfo;
use crate::method_info::MethodInfo;
use crate::my_string;
use crate::object_info::ObjectInfo;
use crate::script::Script;
use std::collections::BTreeMap;
#[derive(Debug)]
pub struct ClassInfo {
pub this_class_name: String,
pub super_class_name: String,
pub method_list: BTreeMap<String, MethodInfo>,
pub object_list: BTreeMap<String, ObjectInfo>,
pub import_list: BTreeMap<String, ImportInfo>,
pub script_list: Script,
}
impl ClassInfo {
pub fn add_file_profix(file_name: &String, class_name: &String) -> String {
if file_name == "main" {
return class_name.clone();
} else if class_name == "BaseObj" || class_name == "TinyObj" {
return class_name.clone();
} else {
return format!("{}_{}", file_name, class_name);
}
}
pub fn new(file_name: &String, define: &String) -> Option<ClassInfo> {
let define = define.strip_prefix("class ").unwrap().to_string();
let define = define.replace(" ", "");
let super_class_name = match my_string::cut(&define, '(', ')') {
Some(s) => s,
None => return None,
};
let super_class_name = match super_class_name.find(".") {
None => ClassInfo::add_file_profix(&file_name, &super_class_name),
Some(x) => super_class_name.replace(".", "_"),
};
let mut this_calss_name = match my_string::get_first_token(&define, '(') {
Some(s) => s,
None => return None,
};
this_calss_name = ClassInfo::add_file_profix(&file_name, &this_calss_name);
let new_class_info = ClassInfo {
this_class_name: this_calss_name,
super_class_name: super_class_name,
method_list: BTreeMap::new(),
object_list: BTreeMap::new(),
import_list: BTreeMap::new(),
script_list: Script::new(),
};
return Some(new_class_info);
}
pub fn push_method(&mut self, method_define: String) {
let method_info = match MethodInfo::new(&self.this_class_name, method_define) {
Some(method) => method,
None => return,
};
self.method_list
.entry(method_info.name.clone())
.or_insert(method_info);
}
pub fn push_import(&mut self, import_define: String, file_name: &String) {
let import_info = match ImportInfo::new(&self.this_class_name, import_define, &file_name) {
Some(import) => import,
None => return,
};
self.import_list
.entry(import_info.import_class_name.clone())
.or_insert(import_info);
}
pub fn push_object(&mut self, object_define: String, file_name: &String) {
let object_info = match ObjectInfo::new(&self.this_class_name, object_define, &file_name) {
Some(object) => object,
None => return,
};
self.object_list
.entry(object_info.name.clone())
.or_insert(object_info);
}
pub fn include(&self) -> String {
let mut include = String::new();
include.push_str(&format!("#include \"{}.h\"\n", self.this_class_name));
include.push_str(&format!("#include \"{}.h\"\n", self.super_class_name));
for (_, import_info) in self.import_list.iter() {
include.push_str(&format!(
"#include \"{}.h\"\n",
import_info.import_class_name
));
}
for (_, object_info) in self.object_list.iter() {
include.push_str(&format!(
"#include \"{}.h\"\n",
object_info.import_class_name
));
}
return include;
}
pub fn method_api_fn(&self) -> String {
let mut method_impl = String::new();
for (_, method_info) in self.method_list.iter() {
method_impl.push_str(&method_info.method_fn_impl());
}
return method_impl;
}
pub fn script_fn(&self) -> String {
let mut script_fn = String::new();
script_fn.push_str("PikaObj * pikaScriptInit(){\r\n");
script_fn.push_str(" PikaObj * pikaMain = newRootObj(\"pikaMain\", New_PikaMain);\r\n");
script_fn.push_str(&self.script_list.content);
script_fn.push_str(" return pikaMain;\r\n");
script_fn.push_str("}\r\n\r\n");
return script_fn;
}
pub fn new_class_fn(&self) -> String {
let mut new_class_fn = String::new();
let new_class_fn_head = format!("{}{{\n", self.new_class_fn_name());
new_class_fn.push_str(&new_class_fn_head);
let derive = format!(" PikaObj *self = New_{}(args);\n", self.super_class_name);
new_class_fn.push_str(&derive);
for (_, import_info) in self.import_list.iter() {
new_class_fn.push_str(&import_info.import_fn());
}
for (_, object_info) in self.object_list.iter() {
new_class_fn.push_str(&object_info.new_object_fn());
}
for (_, method_info) in self.method_list.iter() {
new_class_fn.push_str(&method_info.get_define());
}
new_class_fn.push_str(" return self;\n");
new_class_fn.push_str("}\n");
return new_class_fn;
}
pub fn new_class_fn_name(&self) -> String {
return format!("PikaObj *New_{}(Args *args)", self.this_class_name);
}
pub fn method_impl_declear(&self) -> String {
let mut method_fn_declear = String::new();
for (_, method_info) in self.method_list.iter() {
method_fn_declear.push_str(&method_info.method_impl_declear());
}
return method_fn_declear;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analize() {
assert_eq!(
ClassInfo::new(
&String::from("Pkg"),
&String::from("class Test(SuperTest):")
)
.unwrap()
.this_class_name,
"Pkg_Test"
);
assert_eq!(
ClassInfo::new(
&String::from("Pkg"),
&String::from("class Test(SuperTest):")
)
.unwrap()
.super_class_name,
"Pkg_SuperTest"
);
}
#[test]
fn test_push_method() {
let mut class_info = ClassInfo::new(
&String::from("Pkg"),
&String::from("class Test(SuperTest):"),
)
.unwrap();
class_info.push_method(String::from("def test(data: str)-> str:"));
assert_eq!(
class_info.method_list.get("test").unwrap().class_name,
"Pkg_Test"
);
assert_eq!(class_info.method_list.get("test").unwrap().name, "test");
assert_eq!(
class_info
.method_list
.get("test")
.as_ref()
.unwrap()
.return_type
.as_ref()
.unwrap()
.to_string(),
"str"
);
assert_eq!(
class_info
.method_list
.get("test")
.as_ref()
.unwrap()
.arg_list
.as_ref()
.unwrap()
.to_string(),
"data:str"
);
}
#[test]
fn test_push_object() {
let mut class_info = ClassInfo::new(
&String::from("Pkg"),
&String::from("class Test(SuperTest):"),
)
.unwrap();
class_info.push_object(String::from("testObj = TestObj()"), &"Pkg".to_string());
assert_eq!(
class_info.object_list.get("testObj").unwrap().class_name,
"Pkg_Test"
);
assert_eq!(
class_info.object_list.get("testObj").unwrap().name,
"testObj"
);
assert_eq!(
class_info
.object_list
.get("testObj")
.unwrap()
.import_class_name,
"Pkg_TestObj"
);
assert_eq!(
class_info.object_list.get("testObj").unwrap().name,
"testObj"
);
}
#[test]
fn test_push_import() {
let mut class_info = ClassInfo::new(
&String::from("Pkg"),
&String::from("class Test(SuperTest):"),
)
.unwrap();
class_info.push_import(String::from("TestObj()"), &"Pkg".to_string());
assert_eq!(
class_info
.import_list
.get("Pkg_TestObj")
.unwrap()
.class_name,
"Pkg_Test"
);
assert_eq!(
class_info
.import_list
.get("Pkg_TestObj")
.unwrap()
.import_class_name,
"Pkg_TestObj"
);
}
}

View File

@ -0,0 +1,172 @@
use crate::class_info::ClassInfo;
use crate::script::Script;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::prelude::*;
#[derive(Debug)]
pub struct Compiler {
pub dist_path: String,
pub source_path: String,
pub class_list: BTreeMap<String, ClassInfo>,
pub class_now_name: Option<String>,
}
impl Compiler {
pub fn new(source_path: String, dist_path: String) -> Compiler {
let compiler = Compiler {
dist_path: dist_path.clone(),
source_path: source_path.clone(),
class_now_name: None,
class_list: BTreeMap::new(),
};
return compiler;
}
pub fn analyze_main_line(mut compiler: Compiler, line: String) -> Compiler {
let file_name = "main".to_string();
let class_name = "PikaMain".to_string();
let class_now = match compiler.class_list.get_mut(&"PikaMain".to_string()) {
Some(class_now) => class_now,
None => compiler.class_list.entry(class_name.clone()).or_insert(
ClassInfo::new(
&file_name,
&"class PikaMain(PikaStdLib.SysObj):".to_string(),
)
.unwrap(),
),
};
compiler.class_now_name = Some(class_name.clone());
if line.starts_with("def ") {
class_now.push_method(line);
return compiler;
}
if line.contains("(") && line.contains(")") && line.contains("=") {
if Script::assert(class_now, &line) {
class_now.script_list.add(&line);
return compiler;
}
class_now.push_object(line, &file_name);
return compiler;
}
if line.contains("(") && line.contains(")") {
class_now.script_list.add(&line);
}
return compiler;
}
pub fn analyze_file(mut compiler: Compiler, file_name: String) -> Compiler {
println!("analyzing file: {}{}.py", compiler.source_path, file_name);
let mut file = File::open(format!("{}{}.py", compiler.source_path, file_name)).unwrap();
let mut file_str = String::new();
file.read_to_string(&mut file_str).unwrap();
let lines: Vec<&str> = file_str.split('\n').collect();
/* analyze each line of pikascript-api.py */
for line in lines.iter() {
compiler = Compiler::analyze_line(compiler, line.to_string(), &file_name);
}
return compiler;
}
pub fn analyze_line(mut compiler: Compiler, line: String, file_name: &String) -> Compiler {
let line = line.replace("\r", "");
if line.starts_with("import ") {
let tokens: Vec<&str> = line.split(" ").collect();
let file = tokens[1];
return Compiler::analyze_file(compiler, file.to_string());
}
if line.starts_with("#") {
return compiler;
}
if line.starts_with("class") {
let class_now = match ClassInfo::new(&file_name, &line) {
Some(s) => s,
None => return compiler,
};
let class_name = class_now.this_class_name.clone();
compiler
.class_list
.entry(class_name.clone())
.or_insert(class_now);
compiler.class_now_name = Some(class_name.clone());
return compiler;
}
if line.starts_with(" def ") {
let line = line.strip_prefix(" ").unwrap().to_string();
let class_now = compiler
.class_list
.get_mut(&compiler.class_now_name.clone().unwrap())
.unwrap();
class_now.push_method(line);
return compiler;
}
if line.starts_with(" ")
&& line.contains("(")
&& line.contains(")")
&& line.contains("=")
{
let line = line.strip_prefix(" ").unwrap().to_string();
let class_now = compiler
.class_list
.get_mut(&compiler.class_now_name.clone().unwrap())
.unwrap();
class_now.push_object(line, &file_name);
return compiler;
}
if line.starts_with(" ") && line.contains("(") && line.contains(")") {
let line = line.strip_prefix(" ").unwrap().to_string();
let class_now = compiler
.class_list
.get_mut(&compiler.class_now_name.clone().unwrap())
.unwrap();
class_now.push_import(line, &file_name);
return compiler;
}
if file_name == "main" {
return Compiler::analyze_main_line(compiler, line);
}
return compiler;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analyze() {
let compiler = Compiler::new(String::from(""), String::from(""));
let compiler = Compiler::analyze_line(
compiler,
String::from("class Test(SuperTest):"),
&"Pkg".to_string(),
);
let compiler =
Compiler::analyze_line(compiler, String::from(" def test()"), &"Pkg".to_string());
let compiler = Compiler::analyze_line(
compiler,
String::from(" testObj = TestObj()"),
&"Pkg".to_string(),
);
let compiler = Compiler::analyze_line(
compiler,
String::from(" TestImport()"),
&"Pkg".to_string(),
);
let class_info = compiler.class_list.get("Pkg_Test").unwrap();
let method_info = class_info.method_list.get("test").unwrap();
let object_info = class_info.object_list.get("testObj").unwrap();
let import_info = class_info.import_list.get("Pkg_TestImport").unwrap();
assert_eq!(class_info.this_class_name, "Pkg_Test");
assert_eq!(class_info.super_class_name, "Pkg_SuperTest");
assert_eq!(method_info.name, "test");
assert_eq!(method_info.class_name, "Pkg_Test");
assert_eq!(object_info.name, "testObj");
assert_eq!(object_info.class_name, "Pkg_Test");
assert_eq!(import_info.class_name, "Pkg_Test");
assert_eq!(import_info.import_class_name, "Pkg_TestImport");
}
}

View File

@ -0,0 +1,65 @@
use crate::my_string;
use crate::class_info;
#[derive(Debug)]
pub struct ImportInfo {
pub class_name: String,
pub import_class_name: String,
}
impl ImportInfo {
pub fn new(
class_name: &String,
input_define: String,
file_name: &String,
) -> Option<ImportInfo> {
let define = input_define.replace(" ", "");
let mut import_class_name = match my_string::get_first_token(&define, '(') {
Some(token) => token,
None => return None,
};
import_class_name = match import_class_name.find(".") {
None => class_info::ClassInfo::add_file_profix(&file_name, &import_class_name),
Some(x) => import_class_name.replace(".", "_"),
};
import_class_name = import_class_name.replace(".", "_");
return Some(ImportInfo {
class_name: class_name.clone(),
import_class_name: import_class_name,
});
}
pub fn import_fn(&self) -> String {
return format!(
" obj_import(self, \"{}\", New_{});\n",
self.import_class_name, self.import_class_name
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_import_info() {
assert_eq!(
ImportInfo::new(
&String::from("Test"),
String::from("ImportTest()"),
&"Pkg".to_string()
)
.unwrap()
.import_class_name,
String::from("Pkg_ImportTest")
);
assert_eq!(
ImportInfo::new(
&String::from("Test"),
String::from("ImportTest()"),
&"Pkg".to_string()
)
.unwrap()
.class_name,
String::from("Test")
);
}
}

View File

@ -0,0 +1,106 @@
mod arg_list;
mod class_info;
mod compiler;
mod import_info;
mod method_info;
mod my_string;
mod object_info;
mod py_arg;
mod py_type;
mod script;
use compiler::*;
use std::fs::File;
use std::io::prelude::*;
fn main() {
let mut compiler = Compiler::new(String::from(""), String::from("pikascript-api/"));
compiler = Compiler::analyze_file(compiler, String::from("main"));
/* write to compiler-info about the info */
let mut compiler_info_file =
File::create(format!("{}compiler-info.txt", compiler.dist_path)).unwrap();
let compiler_info = format!("{:?}", compiler);
compiler_info_file.write(compiler_info.as_bytes()).unwrap();
/* make the api.c file for each python class */
for (_, class_info) in compiler.class_list.iter() {
let api_file_path = format!("{}{}-api.c", compiler.dist_path, class_info.this_class_name);
let mut f = File::create(api_file_path).unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write("/* Warning! Don't modify this file! */\n".as_bytes())
.unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write(class_info.include().as_bytes()).unwrap();
f.write("#include <stdio.h>\n".as_bytes()).unwrap();
f.write("#include <stdlib.h>\n".as_bytes()).unwrap();
f.write("#include \"BaseObj.h\"\n".as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
f.write(class_info.method_api_fn().as_bytes()).unwrap();
f.write(class_info.new_class_fn().as_bytes()).unwrap();
}
/* make the .h file for each python class */
for (_, class_info) in compiler.class_list.iter() {
let api_file_path = format!("{}{}.h", compiler.dist_path, class_info.this_class_name);
let mut f = File::create(api_file_path).unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write("/* Warning! Don't modify this file! */\n".as_bytes())
.unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write(format!("#ifndef __{}__H\n", class_info.this_class_name).as_bytes())
.unwrap();
f.write(format!("#define __{}__H\n", class_info.this_class_name).as_bytes())
.unwrap();
f.write("#include <stdio.h>\n".as_bytes()).unwrap();
f.write("#include <stdlib.h>\n".as_bytes()).unwrap();
f.write("#include \"PikaObj.h\"\n".as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
let new_class_fn_declear = format!("{};\n", class_info.new_class_fn_name());
f.write(new_class_fn_declear.as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
f.write(class_info.method_impl_declear().as_bytes())
.unwrap();
f.write("\n".as_bytes()).unwrap();
f.write("#endif\n".as_bytes()).unwrap();
}
/* make the pikascript.c */
let api_file_path = format!("{}pikaScript.c", compiler.dist_path);
let mut f = File::create(api_file_path).unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write("/* Warning! Don't modify this file! */\n".as_bytes())
.unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write("#include \"PikaMain.h\"\n".as_bytes()).unwrap();
f.write("#include <stdio.h>\n".as_bytes()).unwrap();
f.write("#include <stdlib.h>\n".as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
let pika_main = compiler
.class_list
.get_mut(&"PikaMain".to_string())
.unwrap();
f.write(pika_main.script_fn().as_bytes()).unwrap();
/* make the pikascript.h */
let api_file_path = format!("{}pikaScript.h", compiler.dist_path);
let mut f = File::create(api_file_path).unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write("/* Warning! Don't modify this file! */\n".as_bytes())
.unwrap();
f.write("/* ******************************** */\n".as_bytes())
.unwrap();
f.write(format!("#ifndef __{}__H\n", "pikaScript").as_bytes())
.unwrap();
f.write(format!("#define __{}__H\n", "pikaScript").as_bytes())
.unwrap();
f.write("#include <stdio.h>\n".as_bytes()).unwrap();
f.write("#include <stdlib.h>\n".as_bytes()).unwrap();
f.write("#include \"PikaObj.h\"\n".as_bytes()).unwrap();
f.write("#include \"PikaMain.h\"\n".as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
f.write("PikaObj * pikaScriptInit();\n".as_bytes()).unwrap();
f.write("\n".as_bytes()).unwrap();
f.write("#endif\n".as_bytes()).unwrap();
}

View File

@ -0,0 +1,237 @@
use crate::arg_list::ArgList;
use crate::my_string;
use crate::py_type::PyType;
#[derive(Debug)]
pub struct MethodInfo {
pub class_name: String,
pub name: String,
pub arg_list: Option<ArgList>,
pub return_type: Option<PyType>,
}
impl MethodInfo {
pub fn new(class_name: &String, input_define: String) -> Option<MethodInfo> {
let define = match input_define.strip_prefix("def ") {
Some(define) => define.to_string(),
None => return None,
};
let define = define.replace(" ", "");
let name = match my_string::get_first_token(&define, '(') {
Some(token) => token,
None => return None,
};
let arg_list = my_string::cut(&define, '(', ')');
let return_type = match my_string::cut(&define, '>', ':') {
Some(py_type) => Some(PyType::new(&py_type)),
None => None,
};
let method_info = MethodInfo {
name: name,
arg_list: ArgList::new(&arg_list),
return_type: return_type,
class_name: class_name.clone(),
};
return Some(method_info);
}
pub fn get_define(&self) -> String {
let return_token = match &self.return_type {
Some(s) => format!("->{}", s.to_string()),
None => String::from(""),
};
let arg_list = match &self.arg_list {
Some(t) => t.to_string(),
None => String::from(""),
};
let define = format!(
" class_defineMethod(self, \"{}({}){}\", {}_{}Method);\n",
self.name, arg_list, return_token, self.class_name, self.name
);
return define;
}
pub fn method_api_name(&self) -> String {
return format!(
"void {}_{}Method(PikaObj *self, Args *args)",
self.class_name, self.name
);
}
pub fn method_impl_declear(&self) -> String {
let return_type_in_c = match self.return_type.as_ref() {
Some(x) => x.to_c_type(),
None => String::from("void"),
};
let arg_list_in_c = match self.arg_list.as_ref() {
Some(x) => format!(", {}", x.to_c()),
None => String::from(""),
};
return format!(
"{} {}_{}(PikaObj *self{});\n",
return_type_in_c, self.class_name, self.name, arg_list_in_c,
);
}
pub fn method_fn_impl(&self) -> String {
let mut method_fn_impl = "".to_string();
let method_fn_name = format!("{}{{\n", self.method_api_name());
let get_local_args = match &self.arg_list {
Some(x) => x.get_local_args(),
None => "".to_string(),
};
let return_impl = match &self.return_type {
Some(x) => format!(" {}(args, res);\n", x.return_fn()),
None => "".to_string(),
};
let return_type_in_c = match &self.return_type {
Some(x) => format!("{} res = ", x.to_c_type()),
None => "".to_string(),
};
let call_arg_list = match &self.arg_list {
Some(x) => format!(", {}", x.call_arg_list()),
None => "".to_string(),
};
let call_method = format!(
" {}{}_{}(self{});\n",
return_type_in_c, self.class_name, self.name, call_arg_list
);
method_fn_impl.push_str(&method_fn_name);
method_fn_impl.push_str(&get_local_args);
method_fn_impl.push_str(&call_method);
method_fn_impl.push_str(&return_impl);
method_fn_impl.push_str("}\n\n");
return method_fn_impl;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_local_declear() {
let method_info = MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str, test2:int)->str:"),
);
let define = method_info.as_ref().unwrap().method_impl_declear();
let method_fn_impl = method_info.as_ref().unwrap().method_fn_impl();
assert_eq!(define, "char * Test_test(PikaObj *self, char * test, int test2);\n");
assert_eq!(
method_fn_impl,
"void Test_testMethod(PikaObj *self, Args *args){\n char * test = args_getStr(args, \"test\");\n int test2 = args_getInt(args, \"test2\");\n char * res = Test_test(self, test, test2);\n method_returnStr(args, res);\n}\n\n"
);
}
#[test]
fn test_analize() {
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str)->str:")
)
.unwrap()
.name,
String::from("test")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str)->str:")
)
.unwrap()
.return_type
.unwrap()
.to_string(),
String::from("str")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str)->str:")
)
.unwrap()
.arg_list
.unwrap()
.to_string(),
String::from("test:str")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test: str) ->str:")
)
.unwrap()
.name,
String::from("test")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test: str) ->str:")
)
.unwrap()
.return_type
.unwrap()
.to_string(),
String::from("str")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test: str) ->str:")
)
.unwrap()
.arg_list
.unwrap()
.to_string(),
String::from("test:str")
);
assert_eq!(
MethodInfo::new(
&String::from("Test"),
String::from("def test(test: str, test2: int) ->str:")
)
.unwrap()
.arg_list
.unwrap()
.to_string(),
String::from("test:str,test2:int")
);
}
#[test]
fn test_get_define() {
let method_info = MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str, test2:int)->str:"),
);
let define = method_info.unwrap().get_define();
assert_eq!(define, String::from(" class_defineMethod(self, \"test(test:str,test2:int)->str\", Test_testMethod);\n"));
}
#[test]
fn test_get_define_no_return() {
let method_info = MethodInfo::new(
&String::from("Test"),
String::from("def test(test:str, test2:int):"),
);
let define = method_info.unwrap().get_define();
assert_eq!(
define,
String::from(
" class_defineMethod(self, \"test(test:str,test2:int)\", Test_testMethod);\n"
)
);
}
#[test]
fn test_get_define_no_return_no_arg_list() {
let method_info =
MethodInfo::new(&String::from("Test"), String::from("def test():")).unwrap();
let define = method_info.get_define();
let method_fn_name = method_info.method_api_name();
assert_eq!(
define,
String::from(" class_defineMethod(self, \"test()\", Test_testMethod);\n")
);
assert_eq!(
method_fn_name,
String::from("void Test_testMethod(PikaObj *self, Args *args)")
);
}
}

View File

@ -0,0 +1,53 @@
pub fn cut(string: &String, start_char: char, end_char: char) -> Option<String> {
let start_index = match string.find(start_char) {
Some(i) => i,
None => return None,
};
let end_index = match string.rfind(end_char) {
Some(i) => i,
None => return None,
};
if start_index + 1 == end_index {
return None;
}
return Some(string[start_index + 1..end_index].to_string());
}
pub fn get_first_token(string: &String, end_char: char) -> Option<String> {
return match string.split_once(end_char) {
Some(s) => Some(s.0.to_string()),
None => None,
};
}
pub fn get_last_token(string: &String, end_char: char) -> Option<String> {
return match string.rsplit_once(end_char) {
Some(s) => Some(s.1.to_string()),
None => None,
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_my_string() {
assert_eq!(
cut(&String::from("(test)"), '(', ')'),
Some(String::from("test"))
);
assert_eq!(
get_first_token(&String::from("test,"), ',',),
Some(String::from("test"))
);
assert_eq!(
get_first_token(&String::from("test("), '(',),
Some(String::from("test"))
);
assert_eq!(
get_last_token(&String::from("test=Test"), '=',),
Some(String::from("Test"))
);
}
}

View File

@ -0,0 +1,88 @@
use crate::class_info;
use crate::my_string;
#[derive(Debug)]
pub struct ObjectInfo {
pub class_name: String,
pub name: String,
pub import_class_name: String,
}
impl ObjectInfo {
pub fn new(
class_name: &String,
input_define: String,
file_name: &String,
) -> Option<ObjectInfo> {
let define = input_define.replace(" ", "");
let name = match my_string::get_first_token(&define, '=') {
Some(token) => token,
None => return None,
};
let mut import_class_name = match my_string::cut(&define, '=', '(') {
Some(token) => token,
None => return None,
};
import_class_name = match import_class_name.find(".") {
None => class_info::ClassInfo::add_file_profix(&file_name, &import_class_name),
Some(x) => import_class_name.replace(".", "_"),
};
return Some(ObjectInfo {
class_name: class_name.clone(),
name: name,
import_class_name: import_class_name,
});
}
pub fn new_object_fn(&self) -> String {
let mut new_object_fn = String::new();
let import_fn = format!(
" obj_import(self, \"{}\", New_{});\n",
self.import_class_name, self.import_class_name
);
new_object_fn.push_str(&import_fn);
let new_fn = format!(
" obj_newObj(self, \"{}\", \"{}\");\n",
self.name, self.import_class_name
);
new_object_fn.push_str(&new_fn);
return new_object_fn;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_object_info() {
assert_eq!(
ObjectInfo::new(
&String::from("Test"),
String::from("test=ImportTest()"),
&"Pkg".to_string()
)
.unwrap()
.import_class_name,
String::from("Pkg_ImportTest")
);
assert_eq!(
ObjectInfo::new(
&String::from("Test"),
String::from("test=ImportTest()"),
&"Pkg".to_string()
)
.unwrap()
.name,
String::from("test")
);
assert_eq!(
ObjectInfo::new(
&String::from("Test"),
String::from("test=ImportTest()"),
&"Pkg".to_string()
)
.unwrap()
.class_name,
String::from("Test")
);
}
}

View File

@ -0,0 +1,46 @@
use crate::py_type::PyType;
#[derive(Debug)]
pub struct PyArg {
py_type: PyType,
name: String,
}
impl PyArg {
pub fn new(name: &String, type_name: &String) -> PyArg {
let py_arg = PyArg {
name: name.clone(),
py_type: PyType::new(type_name),
};
return py_arg;
}
pub fn name(&self) -> String {
return self.name.clone();
}
pub fn c_type(&self) -> String {
return self.py_type.to_c_type();
}
pub fn get_local_arg(&self) -> String {
return format!(
" {} {} = {}(args, \"{}\");\n",
self.c_type(),
self.name(),
self.py_type.get_fn(),
self.name()
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_arg_to_local() {
let arg = PyArg::new(&"arg".to_string(), &"str".to_string());
assert_eq!(
arg.get_local_arg(),
" char * arg = args_getStr(args, \"arg\");\n"
);
}
}

View File

@ -0,0 +1,78 @@
#[derive(Debug)]
pub struct PyType {
type_name: String,
}
impl PyType {
pub fn to_c_type(&self) -> String {
if self.type_name == "int" {
return "int".to_string();
}
if self.type_name == "float" {
return "float".to_string();
}
if self.type_name == "pointer" {
return "void *".to_string();
}
if self.type_name == "str" {
return "char *".to_string();
}
if self.type_name == "" {
return "void".to_string();
}
return "void *".to_string();
}
pub fn to_string(&self) -> String {
return self.type_name.clone();
}
pub fn new(type_name: &String) -> PyType {
return PyType {
type_name: type_name.clone(),
};
}
pub fn return_fn(&self) -> String {
if self.type_name == "int" {
return "method_returnInt".to_string();
}
if self.type_name == "float" {
return "method_returnFloat".to_string();
}
if self.type_name == "pointer" {
return "method_returnPtr".to_string();
}
if self.type_name == "str" {
return "method_returnStr".to_string();
}
return "method_returnPtr".to_string();
}
pub fn set_fn(&self) -> String {
if self.type_name == "int" {
return "args_setInt".to_string();
}
if self.type_name == "float" {
return "args_setFloat".to_string();
}
if self.type_name == "pointer" {
return "args_setPtr".to_string();
}
if self.type_name == "str" {
return "args_setStr".to_string();
}
return "args_setPtr".to_string();
}
pub fn get_fn(&self) -> String {
if self.type_name == "int" {
return "args_getInt".to_string();
}
if self.type_name == "float" {
return "args_getFloat".to_string();
}
if self.type_name == "pointer" {
return "args_getPtr".to_string();
}
if self.type_name == "str" {
return "args_getStr".to_string();
}
return "args_getPtr".to_string();
}
}

View File

@ -0,0 +1,35 @@
use crate::class_info::ClassInfo;
use crate::my_string;
#[derive(Debug)]
pub struct Script {
pub content: String,
}
impl Script {
pub fn new() -> Script {
return Script {
content: String::new(),
};
}
pub fn add(&mut self, content: &String) {
self.content.push_str(&Script::obj_run(content));
}
pub fn assert(class_info: &ClassInfo, content: &String) -> bool {
let cmd = my_string::cut(content, '=', '(').unwrap();
let cmd = cmd.replace(" ", "");
let called_first_object = match my_string::get_first_token(&cmd, '.') {
Some(token) => token,
None => cmd,
};
for (_, obj_info) in class_info.object_list.iter() {
let obj_name = obj_info.name.clone();
if called_first_object == obj_name {
return true;
}
}
return false;
}
pub fn obj_run(cmd: &String) -> String {
return format!(" obj_run(pikaMain, \"{}\");\r\n", cmd);
}
}