goscript_codegen/
entry.rs

1#![allow(dead_code)]
2use super::codegen::CodeGen;
3use super::emit::{CallStyle, Emitter};
4use super::interface::IfaceMapping;
5use super::package::PkgVarPairs;
6use super::types::TypeCache;
7use goscript_parser::ast::Ident;
8use goscript_parser::errors::ErrorList;
9use goscript_parser::objects::Objects as AstObjects;
10use goscript_parser::objects::*;
11use goscript_parser::FileSet;
12use goscript_types::{Config, PackageKey as TCPackageKey, TCObjects, TypeInfo};
13use goscript_vm::gc::GcoVec;
14use goscript_vm::instruction::*;
15use goscript_vm::null_key;
16use goscript_vm::value::*;
17use goscript_vm::vm::ByteCode;
18use std::collections::HashMap;
19use std::pin::Pin;
20
21pub struct EntryGen<'a> {
22    objects: Pin<Box<VMObjects>>,
23    ast_objs: &'a AstObjects,
24    tc_objs: &'a TCObjects,
25    dummy_gcv: GcoVec,
26    packages: Vec<PackageKey>,
27    iface_mapping: IfaceMapping,
28    // pkg_indices maps TCPackageKey to the index (in the generated code) of the package
29    pkg_indices: HashMap<TCPackageKey, OpIndex>,
30    blank_ident: IdentKey,
31}
32
33impl<'a> EntryGen<'a> {
34    pub fn new(asto: &'a AstObjects, tco: &'a TCObjects, bk: IdentKey) -> EntryGen<'a> {
35        EntryGen {
36            objects: Box::pin(VMObjects::new()),
37            ast_objs: asto,
38            tc_objs: tco,
39            dummy_gcv: GcoVec::new(),
40            packages: Vec::new(),
41            iface_mapping: IfaceMapping::new(),
42            pkg_indices: HashMap::new(),
43            blank_ident: bk,
44        }
45    }
46
47    // generate the entry function for ByteCode
48    fn gen_entry_func(
49        &mut self,
50        pkg: PackageKey,
51        index: OpIndex,
52        main_ident: IdentKey,
53        pairs: &mut PkgVarPairs,
54    ) -> FunctionKey {
55        // import the 0th pkg and call the main function of the pkg
56        let fmeta = self.objects.metadata.default_sig;
57        let f = GosValue::new_function(
58            null_key!(),
59            fmeta.clone(),
60            &mut self.objects,
61            &self.dummy_gcv,
62            FuncFlag::Default,
63        );
64        let fkey = *f.as_function();
65        let func = &mut self.objects.functions[fkey];
66        let mut emitter = Emitter::new(func);
67        emitter.emit_import(index, pkg, None);
68        emitter.emit_load(
69            EntIndex::PackageMember(pkg, main_ident),
70            Some((pairs, fkey)),
71            ValueType::Function,
72            None,
73        );
74        emitter.emit_pre_call(None);
75        emitter.emit_call(CallStyle::Default, false, None);
76        emitter.emit_return(None, None);
77        *f.as_function()
78    }
79
80    pub fn gen(
81        mut self,
82        checker_result: &HashMap<TCPackageKey, TypeInfo>,
83        main_pkg: TCPackageKey,
84        main_ident: IdentKey,
85    ) -> ByteCode {
86        let mut main_pkg_idx = None;
87        for (&tcpkg, _) in checker_result.iter() {
88            // create vm packages and store the indices
89            let name = self.tc_objs.pkgs[tcpkg].name().clone().unwrap();
90            let pkey = self.objects.packages.insert(PackageVal::new(name));
91            self.packages.push(pkey);
92            let index = (self.packages.len() - 1) as OpIndex;
93            self.pkg_indices.insert(tcpkg, index);
94            if tcpkg == main_pkg {
95                main_pkg_idx = Some(index);
96            }
97        }
98        let mut type_cache: TypeCache = HashMap::new();
99        let mut pairs = PkgVarPairs::new();
100        for (i, (tcpkg, ti)) in checker_result.iter().enumerate() {
101            let mut cgen = CodeGen::new(
102                &mut self.objects,
103                self.ast_objs,
104                self.tc_objs,
105                &mut self.dummy_gcv,
106                &ti,
107                &mut type_cache,
108                &mut self.iface_mapping,
109                &self.pkg_indices,
110                &self.packages,
111                self.packages[i],
112                self.blank_ident,
113            );
114            cgen.gen_with_files(&ti.ast_files, *tcpkg, i as OpIndex);
115            pairs.append_from_util(cgen.pkg_util());
116        }
117        let index = main_pkg_idx.unwrap();
118        let entry =
119            self.gen_entry_func(self.packages[index as usize], index, main_ident, &mut pairs);
120        pairs.patch_index(self.ast_objs, &mut self.objects);
121        ByteCode {
122            objects: self.objects,
123            packages: self.packages,
124            ifaces: self.iface_mapping.into_result(),
125            entry: entry,
126        }
127    }
128}
129
130pub fn parse_check_gen(
131    path: &str,
132    config: &Config,
133    fset: &mut FileSet,
134    el: &ErrorList,
135) -> Result<ByteCode, usize> {
136    let asto = &mut AstObjects::new();
137    let tco = &mut goscript_types::TCObjects::new();
138    let results = &mut HashMap::new();
139    let pkgs = &mut HashMap::new();
140
141    let importer =
142        &mut goscript_types::Importer::new(&config, fset, pkgs, results, asto, tco, el, 0);
143    let key = goscript_types::ImportKey::new(path, "./");
144    let main_pkg = importer.import(&key);
145
146    if el.len() > 0 {
147        Err(el.len())
148    } else {
149        let blank_ident = asto.idents.insert(Ident::blank(0));
150        let main_ident = asto.idents.insert(Ident::with_str(0, "main"));
151        let gen = EntryGen::new(asto, tco, blank_ident);
152        Ok(gen.gen(results, main_pkg.unwrap(), main_ident))
153    }
154}