add isbpl compatibility mode for basic programs
This commit is contained in:
parent
fa60d4c1e0
commit
574ea328ed
12 changed files with 159 additions and 45 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -22,7 +22,7 @@ checksum = "b03f7fbd470aa8b3ad163c85cce8bccfc11cc9c44ef12da0a4eddd98bd307352"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spl"
|
name = "spl"
|
||||||
version = "0.2.3"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"multicall",
|
"multicall",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "spl"
|
name = "spl"
|
||||||
version = "0.2.4"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Stack Pogramming Language: A simple, concise scripting language."
|
description = "Stack Pogramming Language: A simple, concise scripting language."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -10,4 +10,4 @@ authors = ["TudbuT"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
readformat = "0.1"
|
readformat = "0.1"
|
||||||
once_cell = "1.17"
|
once_cell = "1.17"
|
||||||
multicall = "0.1.4"
|
multicall = "0.1"
|
||||||
|
|
11
assemble.spl
11
assemble.spl
|
@ -1,5 +1,14 @@
|
||||||
|
|
||||||
func main { mega | with args ;
|
func main { mega | with args ;
|
||||||
2 args:get write-file-sasm println
|
args:len 3 gt if {
|
||||||
|
3 args:get "isbpl" eq if {
|
||||||
|
"const str import-isbpl" println
|
||||||
|
"#isbpl.spl" println
|
||||||
|
"end import-isbpl" println
|
||||||
|
"call import" println
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def file 2 args:get =file
|
||||||
|
file write-file-sasm println
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
23
isbpl.spl
Normal file
23
isbpl.spl
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
native engage-compatibility-mode
|
||||||
|
func # { pop }
|
||||||
|
func puts { print }
|
||||||
|
func fcall { call }
|
||||||
|
func strconcat { concat }
|
||||||
|
func aget { swap :get }
|
||||||
|
func stoi { _mega }
|
||||||
|
func itos { _str }
|
||||||
|
def argv'pre-isbplmod &argv =argv'pre-isbplmod
|
||||||
|
func argv {
|
||||||
|
def args argv'pre-isbplmod call =args
|
||||||
|
def nargs args:len 2 - anew =nargs
|
||||||
|
args nargs 2 0 nargs:len acopy
|
||||||
|
nargs
|
||||||
|
}
|
||||||
|
func inc {
|
||||||
|
"isbpl.spl: ISBPL code tried to call inc, an untranslatable function" println
|
||||||
|
pop
|
||||||
|
}
|
||||||
|
func dec {
|
||||||
|
"isbpl.spl: ISBPL code tried to call inc, an untranslatable function" println
|
||||||
|
pop
|
||||||
|
}
|
|
@ -195,7 +195,8 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
|
||||||
Value::Func(AFunc::new(Func {
|
Value::Func(AFunc::new(Func {
|
||||||
ret_count: 0,
|
ret_count: 0,
|
||||||
to_call: FuncImpl::SPL(
|
to_call: FuncImpl::SPL(
|
||||||
lexer::lex(s).map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
lexer::lex(false, s)
|
||||||
|
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
||||||
),
|
),
|
||||||
run_as_base: false,
|
run_as_base: false,
|
||||||
origin: stack.get_frame(),
|
origin: stack.get_frame(),
|
||||||
|
@ -218,7 +219,8 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
|
||||||
Value::Func(AFunc::new(Func {
|
Value::Func(AFunc::new(Func {
|
||||||
ret_count: 0,
|
ret_count: 0,
|
||||||
to_call: FuncImpl::SPL(
|
to_call: FuncImpl::SPL(
|
||||||
lexer::lex(s).map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
lexer::lex(n.ends_with(".isbpl"), s)
|
||||||
|
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
||||||
),
|
),
|
||||||
run_as_base: true,
|
run_as_base: true,
|
||||||
origin: stack.get_frame(),
|
origin: stack.get_frame(),
|
||||||
|
|
85
src/lexer.rs
85
src/lexer.rs
|
@ -1,6 +1,9 @@
|
||||||
|
mod compat;
|
||||||
|
|
||||||
use std::{mem, sync::Arc};
|
use std::{mem, sync::Arc};
|
||||||
|
|
||||||
use crate::runtime::*;
|
use crate::runtime::*;
|
||||||
|
use compat::match_compat;
|
||||||
use readformat::*;
|
use readformat::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -13,12 +16,16 @@ pub enum LexerError {
|
||||||
ArgsWithoutCall,
|
ArgsWithoutCall,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lex(input: String) -> Result<Words, LexerError> {
|
pub fn lex(compat: bool, input: String) -> Result<Words, LexerError> {
|
||||||
let str_words = parse(input);
|
let str_words = parse(input);
|
||||||
Ok(read_block(&str_words[..], false)?.1)
|
Ok(read_block(&str_words[..], false, compat)?.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, usize), LexerError> {
|
fn read_block(
|
||||||
|
str_words: &[String],
|
||||||
|
isfn: bool,
|
||||||
|
mut compat: bool,
|
||||||
|
) -> Result<(Option<u32>, Words, usize), LexerError> {
|
||||||
if str_words.is_empty() {
|
if str_words.is_empty() {
|
||||||
return Ok((None, Words::new(Vec::new()), 0));
|
return Ok((None, Words::new(Vec::new()), 0));
|
||||||
}
|
}
|
||||||
|
@ -26,45 +33,71 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
let mut words = Vec::new();
|
let mut words = Vec::new();
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
if str_words[0] == "{" && isfn {
|
if str_words[0] == "{" && isfn {
|
||||||
let mut r = 0_u32;
|
let mut r = 0;
|
||||||
while str_words[r as usize + 1] != "|" {
|
while str_words[r + 1] != "|" && !compat {
|
||||||
r += 1;
|
r += 1;
|
||||||
|
if r >= str_words.len() - 1 {
|
||||||
|
r = 0;
|
||||||
|
if !compat {
|
||||||
|
eprintln!("spl: parsing in compatibility mode");
|
||||||
|
compat = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i += r as usize + 2;
|
i += r + 2 - compat as usize;
|
||||||
rem = Some(r);
|
rem = Some(r as u32);
|
||||||
}
|
}
|
||||||
while i < str_words.len() {
|
while i < str_words.len() {
|
||||||
let word = str_words[i].to_owned();
|
let word = str_words[i].to_owned();
|
||||||
|
if compat && match_compat(word.to_owned(), str_words, &mut words, &mut i) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
match word.as_str() {
|
match word.as_str() {
|
||||||
|
"native" => {
|
||||||
|
i += 1;
|
||||||
|
if !compat {
|
||||||
|
eprintln!("spl: parsing in compatibility mode");
|
||||||
|
compat = true;
|
||||||
|
}
|
||||||
|
eprintln!(
|
||||||
|
"spl: [compat] code tried to load a native function `{}`",
|
||||||
|
str_words[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
"def" => {
|
"def" => {
|
||||||
words.push(Word::Key(Keyword::Def(str_words[i + 1].to_owned())));
|
words.push(Word::Key(Keyword::Def(str_words[i + 1].to_owned())));
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
"func" => {
|
"func" => {
|
||||||
|
if compat && str_words[i + 1] == "{" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if let Some(dat) = readf1("func\0{}\0{", str_words[i..=i + 2].join("\0").as_str()) {
|
if let Some(dat) = readf1("func\0{}\0{", str_words[i..=i + 2].join("\0").as_str()) {
|
||||||
let block = read_block(&str_words[i + 2..], true)?;
|
let block = read_block(&str_words[i + 2..], true, compat)?;
|
||||||
i += 2 + block.2;
|
i += 2 + block.2;
|
||||||
words.push(Word::Key(Keyword::Func(
|
words.push(Word::Key(Keyword::Func(
|
||||||
dat.to_owned(),
|
dat.to_owned(),
|
||||||
block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
||||||
block.1,
|
block.1,
|
||||||
)));
|
)));
|
||||||
} else if let Some(dat) =
|
} else if !compat {
|
||||||
readf1("func\0{}\0@rust", str_words[i..=i + 2].join("\0").as_str())
|
if let Some(dat) =
|
||||||
{
|
readf1("func\0{}\0@rust", str_words[i..=i + 2].join("\0").as_str())
|
||||||
i += 3;
|
{
|
||||||
words.push(Word::Key(Keyword::FuncOf(
|
i += 3;
|
||||||
dat.to_owned(),
|
words.push(Word::Key(Keyword::FuncOf(
|
||||||
str_words[i][2..].to_owned(),
|
dat.to_owned(),
|
||||||
FuncImplType::Rust,
|
str_words[i][2..].to_owned(),
|
||||||
)));
|
FuncImplType::Rust,
|
||||||
|
)));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(LexerError::FunctionBlockExpected);
|
return Err(LexerError::FunctionBlockExpected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lambda
|
// lambda
|
||||||
"{" => {
|
"{" => {
|
||||||
let block = read_block(&str_words[i..], true)?;
|
let block = read_block(&str_words[i..], true, compat)?;
|
||||||
i += block.2;
|
i += block.2;
|
||||||
words.push(Word::Const(Value::Func(AFunc::new(Func {
|
words.push(Word::Const(Value::Func(AFunc::new(Func {
|
||||||
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
||||||
|
@ -79,7 +112,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
words.push(Word::Const(Value::Str(x[2..].to_owned())));
|
words.push(Word::Const(Value::Str(x[2..].to_owned())));
|
||||||
}
|
}
|
||||||
"<{" => {
|
"<{" => {
|
||||||
let block = read_block(&str_words[i + 1..], false)?;
|
let block = read_block(&str_words[i + 1..], false, compat)?;
|
||||||
i += block.2 + 1;
|
i += block.2 + 1;
|
||||||
let mut block = block.1.words;
|
let mut block = block.1.words;
|
||||||
match words.remove(words.len() - 1) {
|
match words.remove(words.len() - 1) {
|
||||||
|
@ -122,7 +155,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
if name == "construct" {
|
if name == "construct" {
|
||||||
has_construct = true;
|
has_construct = true;
|
||||||
}
|
}
|
||||||
let block = read_block(&str_words[i + 1..], true)?;
|
let block = read_block(&str_words[i + 1..], true, compat)?;
|
||||||
i += 1 + block.2;
|
i += 1 + block.2;
|
||||||
methods.push((
|
methods.push((
|
||||||
name,
|
name,
|
||||||
|
@ -141,7 +174,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
is_namespace,
|
is_namespace,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
"include" => {
|
"include" if !compat => {
|
||||||
if let Some(x) = readf(
|
if let Some(x) = readf(
|
||||||
"include\0{}\0in\0{}",
|
"include\0{}\0in\0{}",
|
||||||
str_words[i..i + 4].join("\0").as_str(),
|
str_words[i..i + 4].join("\0").as_str(),
|
||||||
|
@ -161,14 +194,14 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
words.push(Word::Key(Keyword::Use(item)));
|
words.push(Word::Key(Keyword::Use(item)));
|
||||||
}
|
}
|
||||||
"while" => {
|
"while" => {
|
||||||
let cond = read_block(&str_words[i + 2..], false)?;
|
let cond = read_block(&str_words[i + 2..], false, compat)?;
|
||||||
i += 2 + cond.2;
|
i += 2 + cond.2;
|
||||||
let blk = read_block(&str_words[i + 2..], false)?;
|
let blk = read_block(&str_words[i + 2..], false, compat)?;
|
||||||
i += 2 + blk.2;
|
i += 2 + blk.2;
|
||||||
words.push(Word::Key(Keyword::While(cond.1, blk.1)));
|
words.push(Word::Key(Keyword::While(cond.1, blk.1)));
|
||||||
}
|
}
|
||||||
"if" => {
|
"if" => {
|
||||||
let blk = read_block(&str_words[i + 2..], false)?;
|
let blk = read_block(&str_words[i + 2..], false, compat)?;
|
||||||
i += 2 + blk.2;
|
i += 2 + blk.2;
|
||||||
words.push(Word::Key(Keyword::If(blk.1)));
|
words.push(Word::Key(Keyword::If(blk.1)));
|
||||||
}
|
}
|
||||||
|
@ -179,9 +212,9 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
types.push(str_words[i].to_owned());
|
types.push(str_words[i].to_owned());
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
let blk = read_block(&str_words[i + 1..], false)?;
|
let blk = read_block(&str_words[i + 1..], false, compat)?;
|
||||||
i += 2 + blk.2;
|
i += 2 + blk.2;
|
||||||
let ctch = read_block(&str_words[i + 1..], false)?;
|
let ctch = read_block(&str_words[i + 1..], false, compat)?;
|
||||||
i += 1 + ctch.2;
|
i += 1 + ctch.2;
|
||||||
words.push(Word::Key(Keyword::Catch(types, blk.1, ctch.1)))
|
words.push(Word::Key(Keyword::Catch(types, blk.1, ctch.1)))
|
||||||
}
|
}
|
||||||
|
|
31
src/lexer/compat.rs
Normal file
31
src/lexer/compat.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use crate::Word;
|
||||||
|
|
||||||
|
pub(crate) fn match_compat(
|
||||||
|
word: String,
|
||||||
|
str_words: &[String],
|
||||||
|
words: &mut Vec<Word>,
|
||||||
|
i: &mut usize,
|
||||||
|
) -> bool {
|
||||||
|
match word.as_str() {
|
||||||
|
"inc" => {
|
||||||
|
eprintln!("spl: [compat] transforming inc call");
|
||||||
|
words.push(Word::Call("++".to_owned(), false, 0));
|
||||||
|
words.push(Word::Call("=".to_owned() + &str_words[*i - 1], false, 0));
|
||||||
|
*i += 1;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
"dec" => {
|
||||||
|
eprintln!("spl: [compat] transforming dec call");
|
||||||
|
words.push(Word::Call("--".to_owned(), false, 0));
|
||||||
|
words.push(Word::Call("=".to_owned() + &str_words[*i - 1], false, 0));
|
||||||
|
*i += 1;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
"include" => {
|
||||||
|
// TODO: translate some stdlib components?
|
||||||
|
words.push(Word::Call("import".to_owned(), false, 0));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
20
src/lib.rs
20
src/lib.rs
|
@ -55,6 +55,14 @@ pub fn start_file_in_runtime(path: &str) -> Result<Stack, Error> {
|
||||||
// import stdlib
|
// import stdlib
|
||||||
add_std(&mut stack)?;
|
add_std(&mut stack)?;
|
||||||
|
|
||||||
|
if path.ends_with(".isbpl") {
|
||||||
|
Words::new(vec![
|
||||||
|
Word::Const(Value::Str("#isbpl.spl".to_owned())),
|
||||||
|
Word::Call("import".to_owned(), false, 0),
|
||||||
|
])
|
||||||
|
.exec(&mut stack)?;
|
||||||
|
}
|
||||||
|
|
||||||
// run file
|
// run file
|
||||||
Words::new(vec![
|
Words::new(vec![
|
||||||
Word::Const(Value::Str(path.to_owned())),
|
Word::Const(Value::Str(path.to_owned())),
|
||||||
|
@ -68,12 +76,12 @@ pub fn start_file_in_runtime(path: &str) -> Result<Stack, Error> {
|
||||||
/// Include the standard library in a runtime-stack-pair, where the runtime has been .set().
|
/// Include the standard library in a runtime-stack-pair, where the runtime has been .set().
|
||||||
pub fn add_std(stack: &mut Stack) -> OError {
|
pub fn add_std(stack: &mut Stack) -> OError {
|
||||||
let f = find_in_splpath("std.spl");
|
let f = find_in_splpath("std.spl");
|
||||||
let words = lex(if let Ok(f) = f {
|
let words = f
|
||||||
fs::read_to_string(f).unwrap()
|
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x}"))))
|
||||||
} else {
|
.and_then(|f| {
|
||||||
f.unwrap_err()
|
lex(f.ends_with(".isbpl"), fs::read_to_string(f).unwrap())
|
||||||
})
|
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))
|
||||||
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?;
|
})?;
|
||||||
words.exec(stack)
|
words.exec(stack)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use spl::{find_in_splpath, lex, oxidizer::RustAppBuilder, start_file_in_runtime, Runtime, SetRuntime};
|
use spl::{
|
||||||
|
find_in_splpath, lex, oxidizer::RustAppBuilder, start_file_in_runtime, Runtime, SetRuntime,
|
||||||
|
};
|
||||||
|
|
||||||
use std::{env::args, fs};
|
use std::{env::args, fs};
|
||||||
|
|
||||||
|
@ -21,15 +23,14 @@ fn main() {
|
||||||
builder.set_name(name);
|
builder.set_name(name);
|
||||||
}
|
}
|
||||||
println!("Embedding source...");
|
println!("Embedding source...");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.set_name(file[..file.rfind('.').unwrap_or(file.len())].to_owned());
|
builder.set_name(file[..file.rfind('.').unwrap_or(file.len())].to_owned());
|
||||||
}
|
}
|
||||||
builder.add_source(file.to_owned(), data.to_owned());
|
builder.add_source(file.to_owned(), data.to_owned());
|
||||||
if build_only {
|
if build_only {
|
||||||
println!("Preparing rust code...");
|
println!("Preparing rust code...");
|
||||||
}
|
}
|
||||||
builder.prepare(lex(data.to_owned()).expect("invalid SPL in natives file."));
|
builder.prepare(lex(false, data.to_owned()).expect("invalid SPL in natives file."));
|
||||||
if build_only {
|
if build_only {
|
||||||
println!("Building...");
|
println!("Building...");
|
||||||
}
|
}
|
||||||
|
|
|
@ -815,7 +815,7 @@ pub fn write_sasm(stack: &mut Stack) -> OError {
|
||||||
require_on_stack!(code, Str, stack, "write-sasm");
|
require_on_stack!(code, Str, stack, "write-sasm");
|
||||||
stack.push(
|
stack.push(
|
||||||
Value::Str(
|
Value::Str(
|
||||||
lexer::lex(code)
|
lexer::lex(false, code)
|
||||||
.map(|x| sasm_write(x))
|
.map(|x| sasm_write(x))
|
||||||
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
.map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?,
|
||||||
)
|
)
|
||||||
|
@ -829,6 +829,7 @@ pub fn write_file_sasm(stack: &mut Stack) -> OError {
|
||||||
stack.push(
|
stack.push(
|
||||||
Value::Str(
|
Value::Str(
|
||||||
lexer::lex(
|
lexer::lex(
|
||||||
|
file.ends_with(".isbpl"),
|
||||||
fs::read_to_string(file).map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?,
|
fs::read_to_string(file).map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?,
|
||||||
)
|
)
|
||||||
.map(|x| sasm_write(x))
|
.map(|x| sasm_write(x))
|
||||||
|
|
|
@ -7,6 +7,9 @@ pub const ITER: &str = include_str!("../iter.spl");
|
||||||
pub const HTTP: &str = include_str!("../http.spl");
|
pub const HTTP: &str = include_str!("../http.spl");
|
||||||
pub const STREAM: &str = include_str!("../stream.spl");
|
pub const STREAM: &str = include_str!("../stream.spl");
|
||||||
pub const MESSAGING: &str = include_str!("../messaging.spl");
|
pub const MESSAGING: &str = include_str!("../messaging.spl");
|
||||||
|
pub const ASSEMBLE: &str = include_str!("../assemble.spl");
|
||||||
|
pub const ISBPL: &str = include_str!("../isbpl.spl");
|
||||||
|
pub const REPL: &str = include_str!("../repl.spl");
|
||||||
|
|
||||||
pub fn register(runtime: &mut Runtime) {
|
pub fn register(runtime: &mut Runtime) {
|
||||||
multicall! {
|
multicall! {
|
||||||
|
@ -17,5 +20,8 @@ pub fn register(runtime: &mut Runtime) {
|
||||||
insert("http.spl", HTTP);
|
insert("http.spl", HTTP);
|
||||||
insert("stream.spl", STREAM);
|
insert("stream.spl", STREAM);
|
||||||
insert("messaging.spl", MESSAGING);
|
insert("messaging.spl", MESSAGING);
|
||||||
|
insert("assemble.spl", ASSEMBLE);
|
||||||
|
insert("isbpl.spl", ISBPL);
|
||||||
|
insert("repl.spl", REPL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
std.spl
4
std.spl
|
@ -6,9 +6,9 @@ func =null { | pop
|
||||||
|
|
||||||
def program-name
|
def program-name
|
||||||
|
|
||||||
def std.alias.print &print =std.alias.print
|
def print'pre-std &print =print'pre-std
|
||||||
func print { |
|
func print { |
|
||||||
_str std.alias.print call
|
_str print'pre-std call
|
||||||
}
|
}
|
||||||
|
|
||||||
func println { |
|
func println { |
|
||||||
|
|
Loading…
Add table
Reference in a new issue