2016-09-17 07:01:45 +00:00
//: Extend 'new' to handle a unicode string literal argument or 'text'.
//: A Mu text is an address to an array of characters.
: ( before " End Mu Types Initialization " )
2018-06-18 02:53:52 +00:00
put ( Type_abbreviations , " text " , new_type_tree ( " &:@:character " ) ) ;
2016-04-24 18:54:30 +00:00
2018-06-16 05:16:09 +00:00
: ( scenario new_string )
2016-04-24 18:54:30 +00:00
def main [
2018-06-24 16:16:17 +00:00
10 : text < - new [ abc def ]
20 : char < - index * 10 : text , 5
2016-04-24 18:54:30 +00:00
]
# number code for 'e'
2018-06-24 16:16:17 +00:00
+ mem : storing 101 in location 20
2016-04-24 18:54:30 +00:00
2018-06-16 05:16:09 +00:00
: ( scenario new_string_handles_unicode )
2016-04-24 18:54:30 +00:00
def main [
2018-06-24 16:16:17 +00:00
10 : text < - new [ a « c ]
20 : num < - length * 10 : text
21 : char < - index * 10 : text , 1
2016-04-24 18:54:30 +00:00
]
2018-06-24 16:16:17 +00:00
+ mem : storing 3 in location 20
2016-04-24 18:54:30 +00:00
# unicode for '«'
2018-06-24 16:16:17 +00:00
+ mem : storing 171 in location 21
2016-04-24 18:54:30 +00:00
: ( before " End NEW Check Special-cases " )
2016-09-17 06:52:15 +00:00
if ( is_literal_text ( inst . ingredients . at ( 0 ) ) ) break ;
2016-04-24 18:54:30 +00:00
: ( before " Convert 'new' To 'allocate' " )
2017-05-07 04:35:46 +00:00
if ( inst . name = = " new " & & ! inst . ingredients . empty ( ) & & is_literal_text ( inst . ingredients . at ( 0 ) ) ) continue ;
2016-04-24 18:54:30 +00:00
: ( after " case NEW " following " Primitive Recipe Implementations " )
2016-09-17 06:52:15 +00:00
if ( is_literal_text ( current_instruction ( ) . ingredients . at ( 0 ) ) ) {
2016-04-24 18:54:30 +00:00
products . resize ( 1 ) ;
2018-06-24 16:16:17 +00:00
products . at ( 0 ) . push_back ( /*alloc id*/ 0 ) ;
2016-09-17 06:52:15 +00:00
products . at ( 0 ) . push_back ( new_mu_text ( current_instruction ( ) . ingredients . at ( 0 ) . name ) ) ;
2017-11-03 08:50:46 +00:00
trace ( " mem " ) < < " new string alloc: " < < products . at ( 0 ) . at ( 0 ) < < end ( ) ;
2016-04-24 18:54:30 +00:00
break ;
}
: ( code )
2016-09-17 06:52:15 +00:00
int new_mu_text ( const string & contents ) {
2016-04-24 18:54:30 +00:00
// allocate an array just large enough for it
int string_length = unicode_length ( contents ) ;
//? Total_alloc += string_length+1;
2016-08-26 20:40:19 +00:00
//? ++Num_alloc;
2018-06-24 16:16:17 +00:00
int result = allocate ( /*array length*/ 1 + string_length ) ;
2018-01-03 08:31:10 +00:00
int curr_address = result ;
2018-06-24 16:16:17 +00:00
+ + curr_address ; // skip alloc id
2017-11-03 08:50:46 +00:00
trace ( " mem " ) < < " storing string length " < < string_length < < " in location " < < curr_address < < end ( ) ;
2016-08-26 18:47:10 +00:00
put ( Memory , curr_address , string_length ) ;
+ + curr_address ; // skip length
2016-04-24 18:54:30 +00:00
int curr = 0 ;
const char * raw_contents = contents . c_str ( ) ;
2016-10-20 05:10:35 +00:00
for ( int i = 0 ; i < string_length ; + + i ) {
2016-04-24 18:54:30 +00:00
uint32_t curr_character ;
assert ( curr < SIZE ( contents ) ) ;
tb_utf8_char_to_unicode ( & curr_character , & raw_contents [ curr ] ) ;
2017-11-03 08:50:46 +00:00
trace ( " mem " ) < < " storing string character " < < curr_character < < " in location " < < curr_address < < end ( ) ;
2016-08-26 18:47:10 +00:00
put ( Memory , curr_address , curr_character ) ;
2016-04-24 18:54:30 +00:00
curr + = tb_utf8_char_length ( raw_contents [ curr ] ) ;
2016-08-26 18:47:10 +00:00
+ + curr_address ;
2016-04-24 18:54:30 +00:00
}
2016-10-22 23:56:07 +00:00
// Mu strings are not null-terminated in memory.
2016-04-24 18:54:30 +00:00
return result ;
}
2016-11-16 07:29:19 +00:00
//: a new kind of typo
2018-06-24 16:16:17 +00:00
: ( scenario literal_text_without_instruction )
2016-11-16 07:29:19 +00:00
% Hide_errors = true ;
def main [
[ abc ]
]
2017-04-04 07:10:47 +00:00
+ error : main : instruction ' [ abc ] ' has no recipe in ' [ abc ] '
2016-11-16 07:29:19 +00:00
2018-06-24 16:16:17 +00:00
//: stash recognizes texts
2016-04-24 18:54:30 +00:00
2018-06-24 16:16:17 +00:00
: ( scenario stash_text )
2016-04-24 18:54:30 +00:00
def main [
2016-09-17 07:06:04 +00:00
1 : text < - new [ abc ]
stash [ foo : ] , 1 : text
2016-04-24 18:54:30 +00:00
]
+ app : foo : abc
2016-11-12 07:30:16 +00:00
: ( before " End inspect Special-cases(r, data) " )
2016-09-17 06:52:15 +00:00
if ( is_mu_text ( r ) ) {
2018-06-24 16:16:17 +00:00
return read_mu_text ( data . at ( /*skip alloc id*/ 1 ) ) ;
2016-04-24 18:54:30 +00:00
}
2016-11-12 09:05:38 +00:00
: ( before " End $print Special-cases " )
else if ( is_mu_text ( current_instruction ( ) . ingredients . at ( i ) ) ) {
2018-06-24 16:16:17 +00:00
cout < < read_mu_text ( ingredients . at ( i ) . at ( /*skip alloc id*/ 1 ) ) ;
2016-11-12 09:05:38 +00:00
}
2018-06-24 16:16:17 +00:00
: ( scenario unicode_text )
2016-04-24 18:54:30 +00:00
def main [
2016-09-17 07:06:04 +00:00
1 : text < - new [ ♠ ]
stash [ foo : ] , 1 : text
2016-04-24 18:54:30 +00:00
]
+ app : foo : ♠
2018-06-24 16:16:17 +00:00
: ( scenario stash_space_after_text )
2016-04-24 18:54:30 +00:00
def main [
2016-09-17 07:06:04 +00:00
1 : text < - new [ abc ]
stash 1 : text , [ foo ]
2016-04-24 18:54:30 +00:00
]
+ app : abc foo
2018-06-24 16:16:17 +00:00
: ( scenario stash_text_as_array )
2016-06-29 16:49:35 +00:00
def main [
2016-09-17 07:06:04 +00:00
1 : text < - new [ abc ]
stash * 1 : text
2016-06-29 16:49:35 +00:00
]
+ app : 3 97 98 99
//: fixes way more than just stash
2016-09-17 06:52:15 +00:00
: ( before " End Preprocess is_mu_text(reagent x) " )
2016-06-29 16:49:35 +00:00
if ( ! canonize_type ( x ) ) return false ;
2018-06-24 16:16:17 +00:00
//: Allocate more to routine when initializing a literal text
: ( scenario new_text_overflow )
% Initial_memory_per_routine = 3 ;
2016-04-24 18:54:30 +00:00
def main [
2018-06-24 16:16:17 +00:00
10 : & : num / raw < - new number : type
20 : text / raw < - new [ a ] # not enough room in initial page , if you take the array length into account
2016-04-24 18:54:30 +00:00
]
2018-06-24 16:16:17 +00:00
+ new : routine allocated memory from 1000 to 1003
+ new : routine allocated memory from 1003 to 1006
2016-04-24 18:54:30 +00:00
//: helpers
: ( code )
int unicode_length ( const string & s ) {
const char * in = s . c_str ( ) ;
int result = 0 ;
int curr = 0 ;
while ( curr < SIZE ( s ) ) { // carefully bounds-check on the string
// before accessing its raw pointer
+ + result ;
curr + = tb_utf8_char_length ( in [ curr ] ) ;
}
return result ;
}
2016-09-17 06:52:15 +00:00
string read_mu_text ( int address ) {
2016-04-24 18:54:30 +00:00
if ( address = = 0 ) return " " ;
2018-06-24 16:16:17 +00:00
int length = get_or_insert ( Memory , address + /*alloc id*/ 1 ) ;
2017-06-15 18:10:15 +00:00
if ( length = = 0 ) return " " ;
2018-06-24 16:16:17 +00:00
return read_mu_characters ( address + /*alloc id*/ 1 + /*length*/ 1 , length ) ;
2017-06-15 18:10:15 +00:00
}
string read_mu_characters ( int start , int length ) {
2016-04-24 18:54:30 +00:00
ostringstream tmp ;
2017-06-15 18:10:15 +00:00
for ( int curr = start ; curr < start + length ; + + curr )
2016-04-24 18:54:30 +00:00
tmp < < to_unicode ( static_cast < uint32_t > ( get_or_insert ( Memory , curr ) ) ) ;
return tmp . str ( ) ;
}
2016-11-12 06:43:43 +00:00
2016-11-27 04:44:52 +00:00
//:: some miscellaneous helpers now that we have text
//: assert: perform sanity checks at runtime
2018-06-24 16:16:17 +00:00
: ( scenario assert_literal )
2018-06-16 05:12:03 +00:00
% Hide_errors = true ; // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
def main [
2018-06-16 05:16:09 +00:00
assert 0 , [ this is an assert in Mu ]
2018-06-16 05:12:03 +00:00
]
+ error : this is an assert in Mu
2018-06-24 16:16:17 +00:00
: ( scenario assert )
% Hide_errors = true ; // '%' lines insert arbitrary C code into tests before calling 'run' with the lines below. Must be immediately after :(scenario) line.
def main [
1 : text < - new [ this is an assert in Mu ]
assert 0 , 1 : text
]
+ error : this is an assert in Mu
2016-11-27 04:44:52 +00:00
: ( before " End Primitive Recipe Declarations " )
ASSERT ,
: ( before " End Primitive Recipe Numbers " )
put ( Recipe_ordinal , " assert " , ASSERT ) ;
: ( before " End Primitive Recipe Checks " )
case ASSERT : {
if ( SIZE ( inst . ingredients ) ! = 2 ) {
2017-05-26 23:43:18 +00:00
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'assert' takes exactly two ingredients rather than ' " < < to_original_string ( inst ) < < " ' \n " < < end ( ) ;
2016-11-27 04:44:52 +00:00
break ;
}
2018-06-24 16:16:17 +00:00
if ( ! is_mu_address ( inst . ingredients . at ( 0 ) ) & & ! is_mu_scalar ( inst . ingredients . at ( 0 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'assert' requires a scalar or address for its first ingredient, but got ' " < < inst . ingredients . at ( 0 ) . original_string < < " ' \n " < < end ( ) ;
2016-11-27 04:44:52 +00:00
break ;
}
if ( ! is_literal_text ( inst . ingredients . at ( 1 ) ) & & ! is_mu_text ( inst . ingredients . at ( 1 ) ) ) {
raise < < maybe ( get ( Recipe , r ) . name ) < < " 'assert' requires a text as its second ingredient, but got ' " < < inst . ingredients . at ( 1 ) . original_string < < " ' \n " < < end ( ) ;
break ;
}
break ;
}
: ( before " End Primitive Recipe Implementations " )
case ASSERT : {
2018-06-24 16:16:17 +00:00
if ( ! scalar_ingredient ( ingredients , 0 ) ) {
2016-11-27 04:44:52 +00:00
if ( is_literal_text ( current_instruction ( ) . ingredients . at ( 1 ) ) )
raise < < current_instruction ( ) . ingredients . at ( 1 ) . name < < ' \n ' < < end ( ) ;
else
2018-06-24 16:16:17 +00:00
raise < < read_mu_text ( ingredients . at ( 1 ) . at ( /*skip alloc id*/ 1 ) ) < < ' \n ' < < end ( ) ;
2017-06-10 21:36:38 +00:00
if ( ! Hide_errors ) exit ( 1 ) ;
2016-11-27 04:44:52 +00:00
}
break ;
}
//: 'cheating' by using the host system
2016-11-12 06:43:43 +00:00
: ( before " End Primitive Recipe Declarations " )
_READ ,
: ( before " End Primitive Recipe Numbers " )
put ( Recipe_ordinal , " $read " , _READ ) ;
: ( before " End Primitive Recipe Checks " )
case _READ : {
break ;
}
: ( before " End Primitive Recipe Implementations " )
case _READ : {
skip_whitespace ( cin ) ;
string result ;
if ( has_data ( cin ) )
cin > > result ;
products . resize ( 1 ) ;
products . at ( 0 ) . push_back ( new_mu_text ( result ) ) ;
break ;
}
: ( code )
void skip_whitespace ( istream & in ) {
while ( true ) {
if ( ! has_data ( in ) ) break ;
if ( isspace ( in . peek ( ) ) ) in . get ( ) ;
else break ;
}
}