1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2022 The Goscript Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

use super::branch::BranchHelper;
use super::codegen::*;
use super::consts::*;
use super::context::*;
use super::package::PkgHelper;
use super::types::{TypeCache, TypeLookup};
use go_parser::ast::Ident;
use go_parser::{AstObjects, ErrorList, FileSet, IdentKey, Map};
use go_types::{
    check::TypeInfo, ImportKey, Importer, PackageKey as TCPackageKey, SourceRead, TCObjects,
    TraceConfig,
};
use go_vm::types::*;
use go_vm::*;
use std::path::Path;
use std::vec;

pub fn parse_check_gen<S: SourceRead>(
    path: &Path,
    tconfig: &TraceConfig,
    reader: &S,
    fset: &mut FileSet,
) -> Result<Bytecode, ErrorList> {
    let ast_objs = &mut AstObjects::new();
    let tc_objs = &mut TCObjects::new();
    let results = &mut Map::new();
    let pkgs = &mut Map::new();
    let el = ErrorList::new();

    let importer = &mut Importer::new(
        &tconfig, reader, fset, pkgs, results, ast_objs, tc_objs, &el, 0,
    );
    let key = ImportKey::new(
        path.to_str().unwrap(),
        reader.working_dir().to_str().unwrap(),
    );
    let main_pkg = importer.import(&key);
    if el.len() > 0 {
        Err(el)
    } else {
        let blank_ident = ast_objs.idents.insert(Ident::blank(0));
        let main_ident = ast_objs.idents.insert(Ident::with_str(0, "main"));
        Ok(gen_byte_code(
            ast_objs,
            tc_objs,
            results,
            main_pkg.unwrap(),
            main_ident,
            blank_ident,
        ))
    }
}

fn gen_byte_code(
    ast_objs: &AstObjects,
    tc_objs: &TCObjects,
    checker_result: &Map<TCPackageKey, TypeInfo>,
    tc_main_pkg: TCPackageKey,
    main_ident: IdentKey,
    blank_ident: IdentKey,
) -> Bytecode {
    let vm_objs = VMObjects::new();
    let mut vmctx = CodeGenVMCtx::new(vm_objs);
    let consts = Consts::new();
    let mut iface_selector = IfaceSelector::new();
    let mut struct_selector = StructSelector::new();
    let mut pkg_map = Map::new();
    let mut type_cache: TypeCache = Map::new();
    let mut branch_helper = BranchHelper::new();
    let mut result_funcs = vec![];

    for (&tcpkg, _) in checker_result.iter() {
        let name = tc_objs.pkgs[tcpkg].name().clone().unwrap();
        let pkey = vmctx.packages_mut().insert(PackageObj::new(name));
        pkg_map.insert(tcpkg, pkey);
    }

    let main_pkg = pkg_map[&tc_main_pkg];
    let entry = gen_entry_func(&mut vmctx, &consts, main_pkg, main_ident);
    let entry_key = entry.f_key;
    result_funcs.push(entry);

    for (tcpkg, ti) in checker_result.iter() {
        let mut pkg_helper = PkgHelper::new(ast_objs, tc_objs, &pkg_map);
        let cgen = CodeGen::new(
            &mut vmctx,
            &consts,
            ast_objs,
            tc_objs,
            &ti,
            &mut type_cache,
            &mut iface_selector,
            &mut struct_selector,
            &mut branch_helper,
            &mut pkg_helper,
            pkg_map[tcpkg],
            blank_ident,
        );
        result_funcs.append(&mut cgen.gen_with_files(&ti.ast_files, *tcpkg));
    }

    let (consts, cst_map) = consts.get_runtime_consts(&mut vmctx);
    for f in result_funcs.into_iter() {
        f.into_runtime_func(ast_objs, &mut vmctx, branch_helper.labels(), &cst_map);
    }

    let dummy_ti = TypeInfo::new();
    let mut lookup = TypeLookup::new(tc_objs, &dummy_ti, &mut type_cache);
    let iface_binding = iface_selector
        .result()
        .into_iter()
        .map(|x| lookup.iface_binding_info(x, &mut vmctx))
        .collect();

    Bytecode::new(
        vmctx.into_vmo(),
        consts,
        iface_binding,
        struct_selector.result(),
        entry_key,
        main_pkg,
    )
}

// generate the entry function for Bytecode
fn gen_entry_func<'a, 'c>(
    vmctx: &'a mut CodeGenVMCtx,
    consts: &'c Consts,
    pkg: PackageKey,
    main_ident: IdentKey,
) -> FuncCtx<'c> {
    let fmeta = vmctx.prim_meta().default_sig;
    let fobj = vmctx.function_with_meta(None, fmeta.clone(), FuncFlag::Default);
    let fkey = *fobj.as_function();
    let mut fctx = FuncCtx::new(fkey, None, consts);
    fctx.emit_import(pkg, None);
    let pkg_addr = fctx.add_package(pkg);
    let index = Addr::PkgMemberIndex(pkg, main_ident);
    fctx.emit_load_pkg(Addr::Regsiter(0), pkg_addr, index, None);
    fctx.emit_call(Addr::Regsiter(0), 0, CallStyle::Default, None);
    fctx.emit_return(None, None, vmctx.functions());
    fctx
}