js,jsdom: Canvas & context API; Added TypeSymbol.is_js_compatible & temporary hacks for JS ifaces (#12526)
parent
258d0d6df7
commit
243e66a106
|
@ -1,82 +1,90 @@
|
||||||
/*
|
|
||||||
import jsdom
|
import jsdom
|
||||||
|
|
||||||
fn get_2dcontext(canvas jsdom.IElement) ?jsdom.CanvasRenderingContext2D {
|
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement {
|
||||||
if canvas is jsdom.HTMLCanvasElement {
|
match elem {
|
||||||
c := canvas.get_context('2d')
|
JS.HTMLCanvasElement {
|
||||||
match c {
|
return elem
|
||||||
jsdom.CanvasRenderingContext2D {
|
}
|
||||||
return c
|
else {
|
||||||
}
|
panic('Not a canvas')
|
||||||
else {
|
|
||||||
return error('cannot fetch 2d context')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return error('canvas is not an HTMLCanvasElement')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_line(context jsdom.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
fn draw_line(mut context JS.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
||||||
context.begin_path()
|
context.beginPath()
|
||||||
context.set_stroke_style('black')
|
context.strokeStyle = 'black'.str
|
||||||
context.set_line_width(1)
|
context.lineWidth = JS.Number(1)
|
||||||
context.move_to(x1, y1)
|
context.moveTo(x1, y1)
|
||||||
context.line_to(x2, y2)
|
context.lineTo(x2, y2)
|
||||||
context.stroke()
|
context.stroke()
|
||||||
context.close_path()
|
context.closePath()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DrawState {
|
struct DrawState {
|
||||||
mut:
|
mut:
|
||||||
|
context JS.CanvasRenderingContext2D
|
||||||
drawing bool
|
drawing bool
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
window := jsdom.window()
|
||||||
document := jsdom.document
|
document := jsdom.document
|
||||||
|
clear_btn := document.getElementById('clearButton'.str) ?
|
||||||
elem := document.get_element_by_id('myButton') ?
|
canvas_elem := document.getElementById('canvas'.str) ?
|
||||||
elemc := document.get_element_by_id('myCanvas') or { panic('no canvas') }
|
canvas := get_canvas(canvas_elem)
|
||||||
canv := jsdom.get_html_canvas_element(elemc) or { panic('expected canvas') }
|
ctx := canvas.getContext('2d'.str, js_undefined()) ?
|
||||||
|
context := match ctx {
|
||||||
context := canv.get_context_2d()
|
JS.CanvasRenderingContext2D {
|
||||||
mut state := DrawState{}
|
ctx
|
||||||
canv.add_event_listener('mousedown', fn [mut state] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
|
||||||
state.drawing = true
|
|
||||||
if event is jsdom.MouseEvent {
|
|
||||||
state.x = event.offset_x()
|
|
||||||
state.y = event.offset_y()
|
|
||||||
}
|
}
|
||||||
})
|
else {
|
||||||
|
panic('can not get 2d context')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut state := DrawState{context, false, 0, 0}
|
||||||
|
|
||||||
canv.add_event_listener('mousemove', fn [context, mut state] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
canvas.addEventListener('mousedown'.str, fn [mut state] (event JS.Event) {
|
||||||
|
state.drawing = true
|
||||||
|
match event {
|
||||||
|
JS.MouseEvent {
|
||||||
|
state.x = int(event.offsetX)
|
||||||
|
state.y = int(event.offsetY)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}, JS.EventListenerOptions{})
|
||||||
|
canvas.addEventListener('mousemove'.str, fn [mut state] (event JS.Event) {
|
||||||
if state.drawing {
|
if state.drawing {
|
||||||
if event is jsdom.MouseEvent {
|
match event {
|
||||||
draw_line(context, state.x, state.y, event.offset_x(), event.offset_y())
|
JS.MouseEvent {
|
||||||
state.x = event.offset_x()
|
draw_line(mut state.context, state.x, state.y, int(event.offsetX),
|
||||||
state.y = event.offset_y()
|
int(event.offsetY))
|
||||||
|
state.x = int(event.offsetX)
|
||||||
|
state.y = int(event.offsetY)
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}, JS.EventListenerOptions{})
|
||||||
|
|
||||||
jsdom.window.add_event_listener('mouseup', fn [context, mut state] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
window.addEventListener('mouseup'.str, fn [mut state] (event JS.Event) {
|
||||||
if state.drawing {
|
if state.drawing {
|
||||||
if event is jsdom.MouseEvent {
|
match event {
|
||||||
draw_line(context, state.x, state.y, event.offset_x(), event.offset_y())
|
JS.MouseEvent {
|
||||||
|
draw_line(mut state.context, state.x, state.y, int(event.offsetX),
|
||||||
|
int(event.offsetY))
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
state.x = 0
|
state.x = 0
|
||||||
state.y = 0
|
state.y = 0
|
||||||
state.drawing = false
|
state.drawing = false
|
||||||
}
|
}
|
||||||
})
|
}, JS.EventListenerOptions{})
|
||||||
elem.add_event_listener('click', fn [context, canv] (_ jsdom.IEventTarget, _ jsdom.IEvent) {
|
clear_btn.addEventListener('click'.str, fn [mut state, canvas] (_ JS.Event) {
|
||||||
context.clear_rect(0, 0, canv.width(), canv.height())
|
state.context.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
})
|
}, JS.EventListenerOptions{})
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
panic('jsdom is being refactored; This example will be available soon')
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<body class="main">
|
<body class="main">
|
||||||
<title>Drawing with mouse events</title>
|
<title>Drawing with mouse events</title>
|
||||||
<input type="button" id="myButton" value="Clear canvas">
|
<input type="button" id="clearButton" value="Clear canvas">
|
||||||
<canvas style="border: 1px solid black;" width="720" height="480" id="myCanvas"></canvas>
|
<canvas style="border: 1px solid black;" width="720" height="480" id="canvas"></canvas>
|
||||||
<script type="text/javascript" src="draw.js"></script>
|
<script type="text/javascript" src="draw.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
|
@ -57,6 +57,34 @@ pub interface JS.Map {
|
||||||
|
|
||||||
pub interface JS.Any {}
|
pub interface JS.Any {}
|
||||||
|
|
||||||
|
pub fn js_is_null(x JS.Any) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = x === null
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn js_is_undefined(x JS.Any) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = x === undefined
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn js_null() JS.Any {
|
||||||
|
mut obj := JS.Any{}
|
||||||
|
#obj = null;
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn js_undefined() JS.Any {
|
||||||
|
mut obj := JS.Any{}
|
||||||
|
#obj = undefined;
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
pub interface JS.Array {
|
pub interface JS.Array {
|
||||||
JS.Any // map(fn (JS.Any) JS.Any) JS.Array
|
JS.Any // map(fn (JS.Any) JS.Any) JS.Array
|
||||||
map(JS.Any) JS.Array
|
map(JS.Any) JS.Array
|
||||||
|
|
|
@ -8,6 +8,13 @@ pub mut:
|
||||||
will_read_frequently bool
|
will_read_frequently bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (settings CanvasRenderingContext2DSettings) to_js() JS.Any {
|
||||||
|
mut object := JS.Any{}
|
||||||
|
#object = { alpha: settings.alpha, colorSpace: settings.color_space.str, desynchronized: settings.desynchronized.val, willReadFrequently: settings.will_read_frequently.val };
|
||||||
|
|
||||||
|
return object
|
||||||
|
}
|
||||||
|
|
||||||
pub interface JS.DOMMatrix2DInit {
|
pub interface JS.DOMMatrix2DInit {
|
||||||
mut:
|
mut:
|
||||||
a JS.Number
|
a JS.Number
|
||||||
|
@ -168,9 +175,9 @@ pub struct JS.EventListenerOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub interface JS.EventTarget {
|
pub interface JS.EventTarget {
|
||||||
addEventListener(cb EventCallback, options JS.EventListenerOptions)
|
addEventListener(event JS.String, cb EventCallback, options JS.EventListenerOptions)
|
||||||
dispatchEvent(event JS.Event) JS.Boolean
|
dispatchEvent(event JS.Event) JS.Boolean
|
||||||
removeEventListener(cb EventCallback, options JS.EventListenerOptions)
|
removeEventListener(event JS.String, cb EventCallback, options JS.EventListenerOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Event is an event which takes place in the DOM.
|
// Event is an event which takes place in the DOM.
|
||||||
|
@ -320,6 +327,7 @@ pub interface JS.Document {
|
||||||
lastModified JS.String
|
lastModified JS.String
|
||||||
inputEncoding JS.String
|
inputEncoding JS.String
|
||||||
implementation JS.DOMImplementation
|
implementation JS.DOMImplementation
|
||||||
|
getElementById(id JS.String) ?JS.HTMLElement
|
||||||
mut:
|
mut:
|
||||||
bgColor JS.String
|
bgColor JS.String
|
||||||
body JS.HTMLElement
|
body JS.HTMLElement
|
||||||
|
@ -368,6 +376,14 @@ pub interface JS.Element {
|
||||||
scroll(x JS.Number, y JS.Number)
|
scroll(x JS.Number, y JS.Number)
|
||||||
scrollBy(x JS.Number, y JS.Number)
|
scrollBy(x JS.Number, y JS.Number)
|
||||||
toggleAttribute(qualifiedName JS.String, force JS.Boolean) JS.Boolean
|
toggleAttribute(qualifiedName JS.String, force JS.Boolean) JS.Boolean
|
||||||
|
getElementsByClassName(className JS.String) JS.HTMLCollection
|
||||||
|
getElementsByTagName(qualifiedName JS.String) JS.HTMLCollection
|
||||||
|
getEelementsByTagNameNS(namespaecURI JS.String, localName JS.String) JS.HTMLCollection
|
||||||
|
hasAttribute(qualifiedName JS.String) JS.Boolean
|
||||||
|
hasAttributeNS(namespace JS.String, localName JS.String) JS.Boolean
|
||||||
|
hasAttributes() JS.Boolean
|
||||||
|
hasPointerCapture(pointerId JS.Number) JS.Boolean
|
||||||
|
matches(selectors JS.String) JS.Boolean
|
||||||
mut:
|
mut:
|
||||||
className JS.String
|
className JS.String
|
||||||
id JS.String
|
id JS.String
|
||||||
|
@ -383,6 +399,13 @@ pub const (
|
||||||
document = JS.Document{}
|
document = JS.Document{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pub fn window() JS.Window {
|
||||||
|
mut x := JS.Any(voidptr(0))
|
||||||
|
#x = window;
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
fn init() {
|
fn init() {
|
||||||
#jsdom__document = document;
|
#jsdom__document = document;
|
||||||
}
|
}
|
||||||
|
@ -398,3 +421,143 @@ pub fn event_listener(callback fn (JS.EventTarget, JS.Event)) EventCallback {
|
||||||
callback(target, event)
|
callback(target, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub interface JS.HTMLCollection {
|
||||||
|
length JS.Number
|
||||||
|
item(idx JS.Number) ?JS.Any
|
||||||
|
namedItem(name JS.String) ?JS.Any
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.HTMLElement {
|
||||||
|
JS.Element
|
||||||
|
accessKeyLabel JS.String
|
||||||
|
offsetHeight JS.Number
|
||||||
|
offsetLeft JS.Number
|
||||||
|
offsetParent JS.Any
|
||||||
|
offsetTop JS.Number
|
||||||
|
offsetWidth JS.Number
|
||||||
|
click()
|
||||||
|
mut:
|
||||||
|
accessKey JS.String
|
||||||
|
autocapitalize JS.String
|
||||||
|
dir JS.String
|
||||||
|
draggable JS.Boolean
|
||||||
|
hidden JS.Boolean
|
||||||
|
innerText JS.String
|
||||||
|
lang JS.String
|
||||||
|
outerText JS.String
|
||||||
|
spellcheck JS.Boolean
|
||||||
|
title JS.String
|
||||||
|
translate JS.Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn JS.HTMLElement.prototype.constructor() JS.HTMLElement
|
||||||
|
|
||||||
|
pub interface JS.HTMLEmbedElement {
|
||||||
|
getSVGDocument() ?JS.Document
|
||||||
|
mut:
|
||||||
|
align JS.String
|
||||||
|
height JS.String
|
||||||
|
src JS.String
|
||||||
|
width JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn html_embed_type(embed JS.HTMLEmbedElement) JS.String {
|
||||||
|
mut str := JS.String{}
|
||||||
|
#str = embed.type
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn JS.HTMLEmbedElement.prototype.constructor() JS.HTMLEmbedElement
|
||||||
|
|
||||||
|
pub type CanvasContext = JS.CanvasRenderingContext2D
|
||||||
|
| JS.WebGL2RenderingContext
|
||||||
|
| JS.WebGLRenderingContext
|
||||||
|
|
||||||
|
pub interface JS.HTMLCanvasElement {
|
||||||
|
JS.HTMLElement
|
||||||
|
getContext(contextId JS.String, options JS.Any) ?CanvasContext
|
||||||
|
mut:
|
||||||
|
height JS.Number
|
||||||
|
width JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type FillStyle = JS.CanvasGradient | JS.CanvasPattern | JS.String
|
||||||
|
|
||||||
|
pub interface JS.CanvasRenderingContext2D {
|
||||||
|
canvas JS.HTMLCanvasElement
|
||||||
|
beginPath()
|
||||||
|
clip(path JS.Path2D, fillRule JS.String)
|
||||||
|
fill(path JS.Path2D, fillRule JS.String)
|
||||||
|
isPointInPath(path JS.Path2D, x JS.Number, y JS.Number, fillRule JS.String) JS.Boolean
|
||||||
|
isPointInStroke(path JS.Path2D, x JS.Number, y JS.Number) JS.Boolean
|
||||||
|
stoke(path JS.Path2D)
|
||||||
|
createLinearGradient(x0 JS.Number, y0 JS.Number, x1 JS.Number, y1 JS.Number) JS.CanvasGradient
|
||||||
|
createRadialGradient(x0 JS.Number, y0 JS.Number, r0 JS.Number, x1 JS.Number, y1 JS.Number, r1 JS.Number) JS.CanvasGradient
|
||||||
|
createPattern(image JS.CanvasImageSource, repetition JS.String) ?JS.CanvasPattern
|
||||||
|
arc(x JS.Number, y JS.Number, radius JS.Number, startAngle JS.Number, endAngle JS.Number, counterclockwise JS.Boolean)
|
||||||
|
arcTo(x1 JS.Number, y1 JS.Number, x2 JS.Number, y2 JS.Number, radius JS.Number)
|
||||||
|
bezierCurveTo(cp1x JS.Number, cp1y JS.Number, cp2x JS.Number, cp2y JS.Number, x JS.Number, y JS.Number)
|
||||||
|
closePath()
|
||||||
|
ellipse(x JS.Number, y JS.Number, radiusX JS.Number, radiusY JS.Number, rotation JS.Number, startAngle JS.Number, endAngle JS.Number, counterclockwise JS.Boolean)
|
||||||
|
lineTo(x JS.Number, y JS.Number)
|
||||||
|
moveTo(x JS.Number, y JS.Number)
|
||||||
|
quadraticCurveTo(cpx JS.Number, cpy JS.Number, x JS.Number, y JS.Number)
|
||||||
|
rect(x JS.Number, y JS.Number, w JS.Number, h JS.Number)
|
||||||
|
getLineDash() JS.Array
|
||||||
|
setLineDash(segments JS.Array)
|
||||||
|
clearRect(x JS.Number, y JS.Number, w JS.Number, h JS.Number)
|
||||||
|
fillRect(x JS.Number, y JS.Number, w JS.null, h JS.Number)
|
||||||
|
strokeRect(x JS.Number, y JS.Number, w JS.Number, h JS.Number)
|
||||||
|
getTransformt() JS.DOMMatrix
|
||||||
|
resetTransform()
|
||||||
|
rotate(angle JS.Number)
|
||||||
|
scale(x JS.Number, y JS.Number)
|
||||||
|
setTransform(matrix JS.DOMMatrix)
|
||||||
|
transform(a JS.Number, b JS.Number, c JS.Number, d JS.Number, e JS.Number, f JS.Number)
|
||||||
|
translate(x JS.Number, y JS.Number)
|
||||||
|
drawFocusIfNeeded(path JS.Path2D, element JS.Element)
|
||||||
|
stroke()
|
||||||
|
mut:
|
||||||
|
lineCap JS.String
|
||||||
|
lineDashOffset JS.Number
|
||||||
|
lineJoin JS.String
|
||||||
|
lineWidth JS.Number
|
||||||
|
miterLimit JS.Number
|
||||||
|
fillStyle FillStyle
|
||||||
|
strokeStyle FillStyle
|
||||||
|
globalAlpha JS.Number
|
||||||
|
globalCompositeOperation JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.CanvasGradient {
|
||||||
|
addColorStop(offset JS.Number, color JS.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.CanvasPattern {
|
||||||
|
setTransform(transform JS.DOMMatrix)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.WebGLRenderingContext {
|
||||||
|
canvas JS.HTMLCanvasElement
|
||||||
|
drawingBufferHeight JS.Number
|
||||||
|
drawingBufferWidth JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.WebGL2RenderingContext {
|
||||||
|
JS.WebGLRenderingContext
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.Window {
|
||||||
|
JS.EventTarget
|
||||||
|
closed JS.Boolean
|
||||||
|
devicePixelRatio JS.Number
|
||||||
|
document JS.Document
|
||||||
|
frameElement JS.Element
|
||||||
|
innerHeight JS.Number
|
||||||
|
innerWidth JS.Number
|
||||||
|
length JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface JS.Path2D {}
|
||||||
|
|
|
@ -267,7 +267,12 @@ pub fn (t &Table) is_same_method(f &Fn, func &Fn) string {
|
||||||
for i in 0 .. f.params.len {
|
for i in 0 .. f.params.len {
|
||||||
// don't check receiver for `.typ`
|
// don't check receiver for `.typ`
|
||||||
has_unexpected_type := i > 0 && f.params[i].typ != func.params[i].typ
|
has_unexpected_type := i > 0 && f.params[i].typ != func.params[i].typ
|
||||||
|
// temporary hack for JS ifaces
|
||||||
|
lsym := t.get_type_symbol(f.params[i].typ)
|
||||||
|
rsym := t.get_type_symbol(func.params[i].typ)
|
||||||
|
if lsym.language == .js && rsym.language == .js {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
has_unexpected_mutability := !f.params[i].is_mut && func.params[i].is_mut
|
has_unexpected_mutability := !f.params[i].is_mut && func.params[i].is_mut
|
||||||
|
|
||||||
if has_unexpected_type || has_unexpected_mutability {
|
if has_unexpected_type || has_unexpected_mutability {
|
||||||
|
|
|
@ -1247,6 +1247,34 @@ pub fn (t &TypeSymbol) find_method_with_generic_parent(name string) ?Fn {
|
||||||
return none
|
return none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_js_compatible returns true if type can be converted to JS type and from JS type back to V type
|
||||||
|
pub fn (t &TypeSymbol) is_js_compatible() bool {
|
||||||
|
mut table := global_table
|
||||||
|
if t.kind == .void {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.kind == .function {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.language == .js || t.name.starts_with('JS.') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
match t.info {
|
||||||
|
SumType {
|
||||||
|
for variant in t.info.variants {
|
||||||
|
sym := table.get_final_type_symbol(variant)
|
||||||
|
if !sym.is_js_compatible() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (t &TypeSymbol) str_method_info() (bool, bool, int) {
|
pub fn (t &TypeSymbol) str_method_info() (bool, bool, int) {
|
||||||
mut has_str_method := false
|
mut has_str_method := false
|
||||||
mut expects_ptr := false
|
mut expects_ptr := false
|
||||||
|
|
|
@ -413,8 +413,10 @@ pub fn (mut c Checker) sum_type_decl(node ast.SumTypeDecl) {
|
||||||
variant.pos)
|
variant.pos)
|
||||||
} else if sym.kind in [.placeholder, .int_literal, .float_literal] {
|
} else if sym.kind in [.placeholder, .int_literal, .float_literal] {
|
||||||
c.error('unknown type `$sym.name`', variant.pos)
|
c.error('unknown type `$sym.name`', variant.pos)
|
||||||
} else if sym.kind == .interface_ {
|
} else if sym.kind == .interface_ && sym.language != .js {
|
||||||
c.error('sum type cannot hold an interface', variant.pos)
|
c.error('sum type cannot hold an interface', variant.pos)
|
||||||
|
} else if sym.kind == .struct_ && sym.language == .js {
|
||||||
|
c.error('sum type cannot hold an JS struct', variant.pos)
|
||||||
}
|
}
|
||||||
if sym.name.trim_prefix(sym.mod + '.') == node.name {
|
if sym.name.trim_prefix(sym.mod + '.') == node.name {
|
||||||
c.error('sum type cannot hold itself', variant.pos)
|
c.error('sum type cannot hold itself', variant.pos)
|
||||||
|
@ -555,8 +557,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
|
||||||
c.ensure_type_exists(method.return_type, method.return_type_pos) or { return }
|
c.ensure_type_exists(method.return_type, method.return_type_pos) or { return }
|
||||||
if is_js {
|
if is_js {
|
||||||
mtyp := c.table.get_type_symbol(method.return_type)
|
mtyp := c.table.get_type_symbol(method.return_type)
|
||||||
if (mtyp.language != .js && !method.return_type.is_void())
|
if !mtyp.is_js_compatible() {
|
||||||
&& !mtyp.name.starts_with('JS.') {
|
|
||||||
c.error('method $method.name returns non JS type', method.pos)
|
c.error('method $method.name returns non JS type', method.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,8 +568,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
|
||||||
c.ensure_type_exists(param.typ, param.pos) or { return }
|
c.ensure_type_exists(param.typ, param.pos) or { return }
|
||||||
if is_js {
|
if is_js {
|
||||||
ptyp := c.table.get_type_symbol(param.typ)
|
ptyp := c.table.get_type_symbol(param.typ)
|
||||||
if (ptyp.kind != .function && ptyp.language != .js
|
if !ptyp.is_js_compatible() && !(j == method.params.len - 1
|
||||||
&& !ptyp.name.starts_with('JS.')) && !(j == method.params.len - 1
|
|
||||||
&& method.is_variadic) {
|
&& method.is_variadic) {
|
||||||
c.error('method `$method.name` accepts non JS type as parameter',
|
c.error('method `$method.name` accepts non JS type as parameter',
|
||||||
method.pos)
|
method.pos)
|
||||||
|
@ -595,7 +595,7 @@ pub fn (mut c Checker) interface_decl(mut node ast.InterfaceDecl) {
|
||||||
c.ensure_type_exists(field.typ, field.pos) or { return }
|
c.ensure_type_exists(field.typ, field.pos) or { return }
|
||||||
if is_js {
|
if is_js {
|
||||||
tsym := c.table.get_type_symbol(field.typ)
|
tsym := c.table.get_type_symbol(field.typ)
|
||||||
if tsym.language != .js && !tsym.name.starts_with('JS.') && tsym.kind != .function {
|
if !tsym.is_js_compatible() {
|
||||||
c.error('field `$field.name` uses non JS type', field.pos)
|
c.error('field `$field.name` uses non JS type', field.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5313,6 +5313,7 @@ pub fn (mut c Checker) expr(node ast.Expr) ast.Type {
|
||||||
defer {
|
defer {
|
||||||
c.expr_level--
|
c.expr_level--
|
||||||
}
|
}
|
||||||
|
|
||||||
// c.expr_level set to 150 so that stack overflow does not occur on windows
|
// c.expr_level set to 150 so that stack overflow does not occur on windows
|
||||||
if c.expr_level > 150 {
|
if c.expr_level > 150 {
|
||||||
c.error('checker: too many expr levels: $c.expr_level ', node.position())
|
c.error('checker: too many expr levels: $c.expr_level ', node.position())
|
||||||
|
@ -6407,6 +6408,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
||||||
} else {
|
} else {
|
||||||
expr_type = expr_types[0].typ
|
expr_type = expr_types[0].typ
|
||||||
}
|
}
|
||||||
|
|
||||||
c.smartcast(node.cond, node.cond_type, expr_type, mut branch.scope)
|
c.smartcast(node.cond, node.cond_type, expr_type, mut branch.scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -620,8 +620,11 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
|
||||||
if is_varg {
|
if is_varg {
|
||||||
g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));')
|
g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));')
|
||||||
} else {
|
} else {
|
||||||
if arg.typ.is_ptr() || arg.is_mut {
|
asym := g.table.get_type_symbol(arg.typ)
|
||||||
g.writeln('$arg_name = new \$ref($arg_name)')
|
if asym.kind != .interface_ && asym.language != .js {
|
||||||
|
if arg.typ.is_ptr() || arg.is_mut {
|
||||||
|
g.writeln('$arg_name = new \$ref($arg_name)')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -743,7 +746,9 @@ fn (mut g JsGen) gen_anon_fn(mut fun ast.AnonFn) {
|
||||||
if is_varg {
|
if is_varg {
|
||||||
g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));')
|
g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));')
|
||||||
} else {
|
} else {
|
||||||
if arg.typ.is_ptr() || arg.is_mut {
|
asym := g.table.get_type_symbol(arg.typ)
|
||||||
|
|
||||||
|
if arg.typ.is_ptr() || (arg.is_mut && asym.kind != .interface_ && asym.language != .js) {
|
||||||
g.writeln('$arg_name = new \$ref($arg_name)')
|
g.writeln('$arg_name = new \$ref($arg_name)')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2343,20 +2343,53 @@ fn (mut g JsGen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var M
|
||||||
} else {
|
} else {
|
||||||
g.write('if (')
|
g.write('if (')
|
||||||
}
|
}
|
||||||
|
if sym.kind == .sum_type || sym.kind == .interface_ {
|
||||||
|
x := branch.exprs[sumtype_index]
|
||||||
|
|
||||||
|
if x is ast.TypeNode {
|
||||||
|
typ := g.unwrap_generic(x.typ)
|
||||||
|
|
||||||
|
tsym := g.table.get_type_symbol(typ)
|
||||||
|
if tsym.language == .js && (tsym.name == 'JS.Number'
|
||||||
|
|| tsym.name == 'JS.Boolean' || tsym.name == 'JS.String') {
|
||||||
|
g.write('typeof ')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
g.match_cond(cond_var)
|
g.match_cond(cond_var)
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
g.write(' instanceof ')
|
x := branch.exprs[sumtype_index]
|
||||||
g.expr(branch.exprs[sumtype_index])
|
if x is ast.TypeNode {
|
||||||
|
typ := g.unwrap_generic(x.typ)
|
||||||
|
tsym := g.table.get_type_symbol(typ)
|
||||||
|
if tsym.language == .js && (tsym.name == 'JS.Number'
|
||||||
|
|| tsym.name == 'JS.Boolean' || tsym.name == 'JS.String') {
|
||||||
|
g.write(' === "${tsym.name[3..].to_lower()}"')
|
||||||
|
} else {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
}
|
||||||
} else if sym.kind == .interface_ {
|
} else if sym.kind == .interface_ {
|
||||||
if !sym.name.starts_with('JS.') {
|
if !sym.name.starts_with('JS.') {
|
||||||
g.write('.val')
|
g.write('.val')
|
||||||
}
|
}
|
||||||
if branch.exprs[sumtype_index] is ast.TypeNode {
|
x := branch.exprs[sumtype_index]
|
||||||
g.write(' instanceof ')
|
if x is ast.TypeNode {
|
||||||
g.expr(branch.exprs[sumtype_index])
|
typ := g.unwrap_generic(x.typ)
|
||||||
|
tsym := g.table.get_type_symbol(typ)
|
||||||
|
if tsym.language == .js && (tsym.name == 'Number'
|
||||||
|
|| tsym.name == 'Boolean' || tsym.name == 'String') {
|
||||||
|
g.write(' === $tsym.name.to_lower()')
|
||||||
|
} else {
|
||||||
|
g.write(' instanceof ')
|
||||||
|
g.expr(branch.exprs[sumtype_index])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.write(' instanceof ')
|
g.write(' instanceof ')
|
||||||
|
|
||||||
g.write('None__')
|
g.write('None__')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue