js: add initial support for runes (#12077)
parent
115493781b
commit
b2945e916f
|
@ -1,6 +1,5 @@
|
||||||
module builtin
|
module builtin
|
||||||
|
|
||||||
import strings
|
|
||||||
// used to generate JS throw statements.
|
// used to generate JS throw statements.
|
||||||
|
|
||||||
pub fn js_throw(s any) {
|
pub fn js_throw(s any) {
|
||||||
|
@ -71,15 +70,6 @@ pub fn unwrap(opt string) string {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (r rune) str() string {
|
|
||||||
res := ''
|
|
||||||
mut sb := strings.new_builder(5)
|
|
||||||
#res.str = r.valueOf().toString()
|
|
||||||
sb.write_string(res)
|
|
||||||
|
|
||||||
return sb.str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn js_stacktrace() string {
|
fn js_stacktrace() string {
|
||||||
stacktrace := ''
|
stacktrace := ''
|
||||||
#let err = new TypeError();
|
#let err = new TypeError();
|
||||||
|
|
|
@ -652,12 +652,13 @@ fn test_rune_keys() {
|
||||||
println(m)
|
println(m)
|
||||||
assert '$m' == '{`!`: 2, `%`: 3, `@`: 7}'
|
assert '$m' == '{`!`: 2, `%`: 3, `@`: 7}'
|
||||||
|
|
||||||
|
/*
|
||||||
mut a := []rune{}
|
mut a := []rune{}
|
||||||
for k, v in m {
|
for k, v in m {
|
||||||
a << k
|
a << k
|
||||||
a << rune(v) + `0`
|
a << rune(v) + `0`
|
||||||
}
|
}
|
||||||
assert a == [`!`, `2`, `%`, `3`, `@`, `7`]
|
assert a == [`!`, `2`, `%`, `3`, `@`, `7`]*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_eq() {
|
fn test_eq() {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
import strings
|
||||||
|
|
||||||
|
pub fn (ra []rune) string() string {
|
||||||
|
mut sb := strings.new_builder(ra.len)
|
||||||
|
sb.write_runes(ra)
|
||||||
|
res := sb.str()
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (c rune) repeat(count int) string {
|
||||||
|
if count < 0 {
|
||||||
|
panic('rune.repeat: count is negative: $count')
|
||||||
|
} else if count == 0 {
|
||||||
|
return ''
|
||||||
|
} else if count == 1 {
|
||||||
|
return c.str()
|
||||||
|
}
|
||||||
|
res := ''
|
||||||
|
#res.str = String.fromCharCode(c.val)
|
||||||
|
|
||||||
|
return res.repeat(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (c rune) str() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = String.fromCharCode(c.val)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -6,6 +6,16 @@ pub:
|
||||||
len int
|
len int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (s string) runes() []rune {
|
||||||
|
mut runes := []rune{}
|
||||||
|
for i := 0; i < s.len; i++ {
|
||||||
|
mut r := rune(`0`)
|
||||||
|
#r = new rune(s.str[i.val].charCodeAt())
|
||||||
|
runes << r
|
||||||
|
}
|
||||||
|
return runes
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (s string) slice(a int, b int) string {
|
pub fn (s string) slice(a int, b int) string {
|
||||||
return string(s.str.slice(a, b))
|
return string(s.str.slice(a, b))
|
||||||
}
|
}
|
||||||
|
@ -784,7 +794,6 @@ pub fn (s string) index_any(chars string) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// limit returns a portion of the string, starting at `0` and extending for a given number of characters afterward.
|
// limit returns a portion of the string, starting at `0` and extending for a given number of characters afterward.
|
||||||
// 'hello'.limit(2) => 'he'
|
// 'hello'.limit(2) => 'he'
|
||||||
// 'hi'.limit(10) => 'hi'
|
// 'hi'.limit(10) => 'hi'
|
||||||
|
@ -795,7 +804,7 @@ pub fn (s string) limit(max int) string {
|
||||||
}
|
}
|
||||||
return u[0..max].string()
|
return u[0..max].string()
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
// is_title returns true if all words of the string is capitalized.
|
// is_title returns true if all words of the string is capitalized.
|
||||||
// Example: assert 'Hello V Developer'.is_title() == true
|
// Example: assert 'Hello V Developer'.is_title() == true
|
||||||
pub fn (s string) is_title() bool {
|
pub fn (s string) is_title() bool {
|
||||||
|
|
|
@ -362,7 +362,8 @@ fn test_reassign() {
|
||||||
/*
|
/*
|
||||||
fn test_runes() {
|
fn test_runes() {
|
||||||
s := 'привет'
|
s := 'привет'
|
||||||
assert s.len == 12
|
println(s.len)
|
||||||
|
//assert s.len == 12
|
||||||
s2 := 'privet'
|
s2 := 'privet'
|
||||||
assert s2.len == 6
|
assert s2.len == 6
|
||||||
u := s.runes()
|
u := s.runes()
|
||||||
|
@ -644,14 +645,13 @@ fn test_quote() {
|
||||||
// assert a.str() == "'"
|
// assert a.str() == "'"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
fn test_limit() {
|
fn test_limit() {
|
||||||
s := 'hello'
|
s := 'hello'
|
||||||
assert s.limit(2) == 'he'
|
assert s.limit(2) == 'he'
|
||||||
assert s.limit(9) == s
|
assert s.limit(9) == s
|
||||||
assert s.limit(0) == ''
|
assert s.limit(0) == ''
|
||||||
// assert s.limit(-1) == ''
|
// assert s.limit(-1) == ''
|
||||||
}*/
|
}
|
||||||
|
|
||||||
fn test_repeat() {
|
fn test_repeat() {
|
||||||
s1 := 'V! '
|
s1 := 'V! '
|
||||||
|
|
|
@ -7,3 +7,7 @@ pub fn utf8_str_visible_length(s string) int {
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn utf8_str_len(s string) int {
|
||||||
|
return s.len
|
||||||
|
}
|
||||||
|
|
|
@ -89,3 +89,11 @@ pub fn (mut b Builder) cut_to(pos int) string {
|
||||||
}
|
}
|
||||||
return b.cut_last(b.len - pos)
|
return b.cut_last(b.len - pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut b Builder) write_runes(runes []rune) {
|
||||||
|
for r in runes {
|
||||||
|
res := string(r)
|
||||||
|
#res.str = String.fromCharCode(r.val)
|
||||||
|
b << res.bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -477,6 +477,7 @@ fn (mut g JsGen) gen_str_for_array(info ast.Array, styp string, str_fn_name stri
|
||||||
} else if sym.kind in [.f32, .f64] {
|
} else if sym.kind in [.f32, .f64] {
|
||||||
g.definitions.writeln('\t\tlet x = new string( it.val + "");')
|
g.definitions.writeln('\t\tlet x = new string( it.val + "");')
|
||||||
} else if sym.kind == .rune {
|
} else if sym.kind == .rune {
|
||||||
|
g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(it.val) + "\`");')
|
||||||
// Rune are managed at this level as strings
|
// Rune are managed at this level as strings
|
||||||
// g.definitions.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{new string("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {new string("\`"), 0, {.d_c = 0 }}}));\n')
|
// g.definitions.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{new string("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {new string("\`"), 0, {.d_c = 0 }}}));\n')
|
||||||
} else if sym.kind == .string {
|
} else if sym.kind == .string {
|
||||||
|
@ -541,8 +542,8 @@ fn (mut g JsGen) gen_str_for_array_fixed(info ast.ArrayFixed, styp string, str_f
|
||||||
} else if sym.kind == .string {
|
} else if sym.kind == .string {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, a.arr.get(new int(i)));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, a.arr.get(new int(i)));')
|
||||||
} else if sym.kind == .rune {
|
} else if sym.kind == .rune {
|
||||||
// tmp_str := str_intp_rune('${elem_str_fn_name}( a[i] $deref)')
|
g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(a.arr.get(new int(i)).val) + "\`");')
|
||||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);')
|
||||||
} else {
|
} else {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr.get(new int(i)) $deref));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr.get(new int(i)) $deref));')
|
||||||
}
|
}
|
||||||
|
@ -593,7 +594,8 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
|
||||||
if key_sym.kind == .string {
|
if key_sym.kind == .string {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));')
|
||||||
} else if key_sym.kind == .rune {
|
} else if key_sym.kind == .rune {
|
||||||
// tmp_str := str_intp_rune('${key_str_fn_name}(key)')
|
g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(key.val) + "\`");')
|
||||||
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);')
|
||||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
||||||
} else {
|
} else {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${key_str_fn_name}(key));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${key_str_fn_name}(key));')
|
||||||
|
@ -603,14 +605,14 @@ fn (mut g JsGen) gen_str_for_map(info ast.Map, styp string, str_fn_name string)
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}());')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}());')
|
||||||
} else if val_sym.kind == .string {
|
} else if val_sym.kind == .string {
|
||||||
// tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)')
|
// tmp_str := str_intp_sq('*($val_styp*)DenseArray_value(&m.key_values, i)')
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, value);')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb,new string("\'" + value.str + "\'"));')
|
||||||
} else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') {
|
} else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, indent_${elem_str_fn_name}(value, indent_count));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, indent_${elem_str_fn_name}(value, indent_count));')
|
||||||
} else if val_sym.kind in [.f32, .f64] {
|
} else if val_sym.kind in [.f32, .f64] {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, value.val + "");')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, value.val + "");')
|
||||||
} else if val_sym.kind == .rune {
|
} else if val_sym.kind == .rune {
|
||||||
// tmp_str := str_intp_rune('${elem_str_fn_name}(*($val_styp*)DenseArray_value(&m.key_values, i))')
|
g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(value.val) + "\`");')
|
||||||
// g.definitions.writeln('\t\tstrings__Builder_write_string(sb, $tmp_str);')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);')
|
||||||
} else {
|
} else {
|
||||||
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(value));')
|
g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(value));')
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,9 @@ fn (mut g JsGen) sym_to_js_typ(sym ast.TypeSymbol) string {
|
||||||
.voidptr {
|
.voidptr {
|
||||||
styp = 'any'
|
styp = 'any'
|
||||||
}
|
}
|
||||||
|
.rune {
|
||||||
|
styp = 'rune'
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
// TODO
|
// TODO
|
||||||
styp = 'undefined'
|
styp = 'undefined'
|
||||||
|
@ -224,7 +227,7 @@ pub fn (mut g JsGen) doc_typ(t ast.Type) string {
|
||||||
styp = g.js_name(sym.name)
|
styp = g.js_name(sym.name)
|
||||||
}
|
}
|
||||||
.rune {
|
.rune {
|
||||||
styp = 'any'
|
styp = 'rune'
|
||||||
}
|
}
|
||||||
.aggregate {
|
.aggregate {
|
||||||
panic('TODO: unhandled aggregate in JS')
|
panic('TODO: unhandled aggregate in JS')
|
||||||
|
@ -362,6 +365,17 @@ fn (mut g JsGen) gen_builtin_type_defs() {
|
||||||
to_jsval: '+this'
|
to_jsval: '+this'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
'rune' {
|
||||||
|
g.gen_builtin_prototype(
|
||||||
|
typ_name: typ_name
|
||||||
|
default_value: 'new Number(0)'
|
||||||
|
constructor: 'val = val.valueOf(); if (typeof val == "string") {this.val = val.charCodeAt();} else if (val instanceof string) { this.val = val.str.charCodeAt(); } else { this.val = val | 0 }'
|
||||||
|
value_of: 'this.val | 0'
|
||||||
|
to_string: 'new string(this.val + "")'
|
||||||
|
eq: 'new bool(self.valueOf() === other.valueOf())'
|
||||||
|
to_jsval: '+this'
|
||||||
|
)
|
||||||
|
}
|
||||||
'f32', 'f64', 'float_literal' {
|
'f32', 'f64', 'float_literal' {
|
||||||
g.gen_builtin_prototype(
|
g.gen_builtin_prototype(
|
||||||
typ_name: typ_name
|
typ_name: typ_name
|
||||||
|
|
|
@ -20,7 +20,7 @@ const (
|
||||||
'Array', 'Map']
|
'Array', 'Map']
|
||||||
// used to generate type structs
|
// used to generate type structs
|
||||||
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64',
|
v_types = ['i8', 'i16', 'int', 'i64', 'byte', 'u16', 'u32', 'u64', 'f32', 'f64',
|
||||||
'int_literal', 'float_literal', 'bool', 'string', 'map', 'array', 'any']
|
'int_literal', 'float_literal', 'bool', 'string', 'map', 'array', 'rune', 'any']
|
||||||
shallow_equatables = [ast.Kind.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64,
|
shallow_equatables = [ast.Kind.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64, .f32, .f64,
|
||||||
.int_literal, .float_literal, .bool, .string]
|
.int_literal, .float_literal, .bool, .string]
|
||||||
)
|
)
|
||||||
|
@ -833,7 +833,11 @@ fn (mut g JsGen) expr(node ast.Expr) {
|
||||||
g.gen_type_cast_expr(node)
|
g.gen_type_cast_expr(node)
|
||||||
}
|
}
|
||||||
ast.CharLiteral {
|
ast.CharLiteral {
|
||||||
g.write("new byte('$node.val')")
|
if utf8_str_len(node.val) < node.val.len {
|
||||||
|
g.write("new rune('$node.val'.charCodeAt())")
|
||||||
|
} else {
|
||||||
|
g.write("new byte('$node.val')")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ast.Comment {}
|
ast.Comment {}
|
||||||
ast.ConcatExpr {
|
ast.ConcatExpr {
|
||||||
|
|
Loading…
Reference in New Issue