js: add fixes for generic structures and functions; add promise API; refactor modules (#12575)

pull/12580/head
playX 2021-11-25 17:49:53 +03:00 committed by GitHub
parent ac3910b8c2
commit f584e70cf2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1170 additions and 54 deletions

View File

@ -1,4 +1,4 @@
import jsdom
import js.dom
import math
const (
@ -198,7 +198,8 @@ const (
)
fn get_webgl() (&JS.HTMLCanvasElement, JS.WebGLRenderingContext) {
elem := jsdom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
JS.console.log(dom.document)
elem := dom.document.getElementById('myCanvas'.str) or { panic('cannot get canvas') }
match elem {
JS.HTMLCanvasElement {
webgl := elem.getContext('experimental-webgl'.str, js_undefined()) or {
@ -326,21 +327,20 @@ fn animate(mut state State, time f64) {
rotate_x(mut state.mo_matrix, state.phi)
rotate_y(mut state.mo_matrix, state.theta)
state.time_old = time
state.gl.enable(jsdom.gl_depth_test())
state.gl.enable(dom.gl_depth_test())
state.gl.clearColor(0.5, 0.5, 0.5, 0.9)
state.gl.clearDepth(1.0)
state.gl.viewport(0.0, 0.0, state.canvas.width, state.canvas.height)
state.gl.clear(JS.Number(int(jsdom.gl_color_buffer_bit()) | int(jsdom.gl_depth_buffer_bit())))
state.gl.clear(JS.Number(int(dom.gl_color_buffer_bit()) | int(dom.gl_depth_buffer_bit())))
state.gl.uniformMatrix4fv(state.pmatrix, JS.Boolean(false), state.proj_matrix.to_number_array())
state.gl.uniformMatrix4fv(state.vmatrix, JS.Boolean(false), state.view_matrix.to_number_array())
state.gl.uniformMatrix4fv(state.mmatrix, JS.Boolean(false), state.mo_matrix.to_number_array())
state.gl.bindBuffer(jsdom.gl_element_array_buffer(), state.index_buffer)
state.gl.drawElements(jsdom.gl_triangles(), indices.len, jsdom.gl_unsigned_short(),
0)
state.gl.bindBuffer(dom.gl_element_array_buffer(), state.index_buffer)
state.gl.drawElements(dom.gl_triangles(), indices.len, dom.gl_unsigned_short(), 0)
jsdom.window().requestAnimationFrame(fn [mut state] (time JS.Number) {
dom.window().requestAnimationFrame(fn [mut state] (time JS.Number) {
animate(mut state, f64(time))
})
}
@ -349,29 +349,29 @@ fn main() {
canvas, gl := get_webgl()
vertex_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_array_buffer(), vertex_buffer)
gl.bufferData(jsdom.gl_array_buffer(), float32_array(vertices), jsdom.gl_static_draw())
gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
gl.bufferData(dom.gl_array_buffer(), float32_array(vertices), dom.gl_static_draw())
color_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_array_buffer(), color_buffer)
gl.bufferData(jsdom.gl_array_buffer(), float32_array(colors), jsdom.gl_static_draw())
gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
gl.bufferData(dom.gl_array_buffer(), float32_array(colors), dom.gl_static_draw())
index_buffer := gl.createBuffer() ?
gl.bindBuffer(jsdom.gl_element_array_buffer(), index_buffer)
gl.bufferData(jsdom.gl_element_array_buffer(), uint16_array(indices), jsdom.gl_static_draw())
gl.bindBuffer(dom.gl_element_array_buffer(), index_buffer)
gl.bufferData(dom.gl_element_array_buffer(), uint16_array(indices), dom.gl_static_draw())
vert_shader := gl.createShader(jsdom.gl_vertex_shader()) ?
vert_shader := gl.createShader(dom.gl_vertex_shader()) ?
gl.shaderSource(vert_shader, vert_code.str)
gl.compileShader(vert_shader)
if !bool(JS.Boolean(gl.getShaderParameter(vert_shader, jsdom.gl_compile_status()))) {
if !bool(JS.Boolean(gl.getShaderParameter(vert_shader, dom.gl_compile_status()))) {
panic('An error occurred when compiling vertex shader: ${string(gl.getShaderInfoLog(vert_shader))}')
}
frag_shader := gl.createShader(jsdom.gl_fragment_shader()) ?
frag_shader := gl.createShader(dom.gl_fragment_shader()) ?
gl.shaderSource(frag_shader, frag_code.str)
gl.compileShader(frag_shader)
if !bool(JS.Boolean(gl.getShaderParameter(frag_shader, jsdom.gl_compile_status()))) {
if !bool(JS.Boolean(gl.getShaderParameter(frag_shader, dom.gl_compile_status()))) {
panic('An error occurred when compiling fragment shader: ${string(gl.getShaderInfoLog(frag_shader))}')
}
@ -380,7 +380,7 @@ fn main() {
gl.attachShader(shader_program, frag_shader)
gl.linkProgram(shader_program)
if !bool(JS.Boolean(gl.getProgramParameter(shader_program, jsdom.gl_link_status()))) {
if !bool(JS.Boolean(gl.getProgramParameter(shader_program, dom.gl_link_status()))) {
panic('unable to initialize the shader program: ${string(gl.getProgramInfoLog(shader_program))}')
}
@ -388,15 +388,15 @@ fn main() {
vmatrix := gl.getUniformLocation(shader_program, 'Vmatrix'.str) ?
mmatrix := gl.getUniformLocation(shader_program, 'Mmatrix'.str) ?
gl.bindBuffer(jsdom.gl_array_buffer(), vertex_buffer)
gl.bindBuffer(dom.gl_array_buffer(), vertex_buffer)
position := gl.getAttribLocation(shader_program, 'position'.str)
gl.vertexAttribPointer(position, JS.Number(3), jsdom.gl_float(), JS.Boolean(false),
gl.vertexAttribPointer(position, JS.Number(3), dom.gl_float(), JS.Boolean(false),
JS.Number(0), JS.Number(0))
gl.enableVertexAttribArray(position)
gl.bindBuffer(jsdom.gl_array_buffer(), color_buffer)
gl.bindBuffer(dom.gl_array_buffer(), color_buffer)
color := gl.getAttribLocation(shader_program, 'color'.str)
gl.vertexAttribPointer(color, JS.Number(3), jsdom.gl_float(), JS.Boolean(false), JS.Number(0),
gl.vertexAttribPointer(color, JS.Number(3), dom.gl_float(), JS.Boolean(false), JS.Number(0),
JS.Number(0))
gl.enableVertexAttribArray(color)
gl.useProgram(shader_program)

View File

@ -1,4 +1,6 @@
<body>
<canvas width="570" height="570" id="myCanvas"></canvas>
<script src="cube.js"></script>
<script src="cube.js">
</script>
</body>

View File

@ -1,4 +1,4 @@
import jsdom
import js.dom
fn get_canvas(elem JS.HTMLElement) &JS.HTMLCanvasElement {
match elem {
@ -30,8 +30,8 @@ mut:
}
fn main() {
window := jsdom.window()
document := jsdom.document
window := dom.window()
document := dom.document
clear_btn := document.getElementById('clearButton'.str) ?
canvas_elem := document.getElementById('canvas'.str) ?
canvas := get_canvas(canvas_elem)

View File

@ -0,0 +1,979 @@
module dom
pub struct CanvasRenderingContext2DSettings {
pub mut:
alpha bool
color_space string
desynchronized 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 {
mut:
a JS.Number
b JS.Number
c JS.Number
d JS.Number
e JS.Number
f JS.Number
m11 JS.Number
m12 JS.Number
m21 JS.Number
m22 JS.Number
m41 JS.Number
m42 JS.Number
}
pub interface JS.DOMMatrixInit {
JS.DOMMatrix2DInit
is2D JS.Boolean
mut:
m13 JS.Number
m14 JS.Number
m23 JS.Number
m24 JS.Number
m31 JS.Number
m32 JS.Number
m33 JS.Number
m34 JS.Number
m43 JS.Number
m44 JS.Number
}
pub interface JS.DOMMatrix {
is2D JS.Boolean
isIdentity JS.Boolean
flipX() JS.DOMMatrix
flipY() JS.DOMMatrix
inverse() JS.DOMMatrix
multiply(other JS.DOMMatrix) JS.DOMMatrix
rotate(rotX JS.Number, rotY JS.Number, rotZ JS.Number) JS.DOMMatrix
rotateAxisAngle(x JS.Number, y JS.Number, z JS.Number, angle JS.Number) JS.DOMMatrix
scale(scaleX JS.Number, scaleY JS.Number, scaleZ JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
scale3d(scale JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
skewX(sx JS.Number) JS.DOMMatrix
skewY(sy JS.Number) JS.DOMMatrix
translate(tx JS.Number, ty JS.Number, tz JS.Number) JS.DOMMatrix
invertSelf() JS.DOMMatrix
multiplySelf(other JS.DOMMatrix) JS.DOMMatrix
preMultiplySelf(other JS.DOMMatrix) JS.DOMMatrix
rotateAxisAngleSelf(x JS.Number, y JS.Number, z JS.Number, angle JS.Number) JS.DOMMatrix
rotateFromVectorSelf(x JS.Number, y JS.Number) JS.DOMMatrix
rotateSelf(rotX JS.Number, rotY JS.Number, rotZ JS.Number) JS.DOMMatrix
scale3dSelf(scale JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
scaleSelf(scaleX JS.Number, scaleY JS.Number, scaleZ JS.Number, originX JS.Number, originY JS.Number, originZ JS.Number) JS.DOMMatrix
toString() JS.String
mut:
a JS.Number
b JS.Number
c JS.Number
d JS.Number
e JS.Number
f JS.Number
m11 JS.Number
m12 JS.Number
m13 JS.Number
m14 JS.Number
m21 JS.Number
m22 JS.Number
m23 JS.Number
m24 JS.Number
m31 JS.Number
m32 JS.Number
m33 JS.Number
m34 JS.Number
m41 JS.Number
m42 JS.Number
m43 JS.Number
m44 JS.Number
}
pub type SVGMatrix = JS.DOMMatrix
pub type WebKitCSSMatrix = JS.DOMMatrix
[use_new]
pub fn JS.DOMMatrix.prototype.constructor(init JS.Array) JS.DOMMatrix
pub interface JS.DOMPoint {
matrixTransform(matrix JS.DOMMatrix) JS.DOMPoint
mut:
w JS.Number
x JS.Number
y JS.Number
z JS.Number
}
[use_new]
pub fn JS.DOMPoint.prototype.constructor(x JS.Number, y JS.Number, z JS.Number, w JS.Number) JS.DOMPoint
pub interface JS.DOMQuad {
p1 JS.DOMPoint
p2 JS.DOMPoint
p3 JS.DOMPoint
p4 JS.DOMPoint
getBounds() JS.DOMRect
}
[use_new]
pub fn JS.DOMQuad.prototype.constructor(p1 JS.DOMPoint, p2 JS.DOMPoint, p3 JS.DOMPoint, p4 JS.DOMPoint) JS.DOMQuad
pub fn JS.DOMQuad.fromQuad(other JS.DOMQuad) JS.DOMQuad
pub fn JS.DOMQuad.fromRect(other JS.DOMRect) JS.DOMRect
pub interface JS.DOMRect {
bottom JS.Number
left JS.Number
right JS.Number
top JS.Number
mut:
height JS.Number
width JS.Number
x JS.Number
y JS.Number
}
[use_new]
pub fn JS.DOMRect.prototype.constructor(x JS.Number, y JS.Number, width JS.Number, height JS.Number) JS.DOMRect
pub interface JS.DOMStringList {
length JS.Number
contains(JS.String) JS.Boolean
item(index JS.Number) ?JS.String
}
pub interface JS.DOMRectList {
length JS.Number
contains(JS.String) JS.Boolean
item(index JS.Number) ?JS.Rect
}
pub type DOMTokenListForEachCb = fn (JS.String, JS.Number, JS.DOMTokenList)
pub interface JS.DOMTokenList {
length JS.Number
toString() JS.String
add(tokens ...JS.Any) ?JS.Any
contains(token JS.String) JS.Boolean
item(index JS.Number) ?JS.String
remove(tokens ...JS.Any) ?JS.Any
replace(token JS.String, newToken JS.String) JS.Boolean
supports(token JS.String) JS.Boolean
toggle(token JS.String, force JS.Boolean) JS.Boolean
forEach(cb DOMTokenListForEachCb, thisArg JS.Any)
mut:
value JS.String
}
pub struct JS.EventListenerOptions {
capture bool
}
pub interface JS.EventTarget {
addEventListener(event JS.String, cb EventCallback, options JS.EventListenerOptions)
dispatchEvent(event JS.Event) JS.Boolean
removeEventListener(event JS.String, cb EventCallback, options JS.EventListenerOptions)
}
pub interface JS.Node {
JS.EventTarget
baseURI JS.String
childNodes JS.Any
firstChild JS.ChildNode
isConnected JS.Boolean
lastChild JS.ChildNode
nextSibling JS.ChildNode
nodeName JS.String
nodeType JS.Number
ownerDocument JS.Document
parentElement JS.HTMLElement
parentNode JS.ParentNode
previousSibling JS.ChildNode
appendChild(node JS.Node) JS.Node
cloneNode(deep JS.Boolean) JS.Node
compareDocumentPosition(other JS.Node) JS.Number
contains(other JS.Node) JS.Boolean
getRootNode(composed JS.Boolean) JS.Node
hasChildNodes() JS.Boolean
insertBefore(node JS.Node, child JS.Node) JS.Node
isEqualNode(otherNode JS.Node) JS.Boolean
isSameNode(otherNode JS.Node) JS.Boolean
lookupPrefix(namespace JS.String) JS.String
normalize()
removeChild(child JS.Node) JS.Node
replaceChild(node JS.Node, child JS.Node) JS.Npde
mut:
nodeValue JS.String
textContent JS.String
}
pub interface JS.ChildNode {
JS.Node
after(nodes ...JS.Any)
before(nodes ...JS.Any)
remove()
replaceWith(nodes ...JS.Any)
}
pub interface JS.ParentNode {
JS.Node
childElementCount JS.Number
children JS.HTMLCollection
}
pub type WindowProxy = JS.Window
pub interface JS.Document {
JS.Node
all JS.HTMLAllCollection
anchros JS.HTMLCollection
applets JS.HTMLCollection
characterSet JS.String
charset JS.String
compatMode JS.String
contentType JS.String
documentURI JS.String
documentElement JS.HTMLElement
hidden JS.Boolean
head JS.HTMLHeadElement
fullscreenEnabled JS.Boolean
fullscreen JS.Boolean
lastModified JS.String
inputEncoding JS.String
implementation JS.DOMImplementation
doctype JS.DocumentType
embeds JS.HTMLCollection
forms JS.HTMLCollection
getElementById(id JS.String) ?JS.HTMLElement
adoptNode(node JS.Node) JS.Node
close()
createAttribute(name JS.String) JS.Attr
createAttributeNS(namespace JS.String, qualifiedName JS.String) JS.Attr
createCDATASection(data JS.String) JS.CDATASection
createComment(data JS.String) JS.Comment
createDocumentFragment() JS.DocumentFragment
createElement(tagName JS.String) JS.HTMLElement
createElementNS(namespaceURI JS.String, qualifiedName JS.String) JS.Element
createEvent(event JS.String) JS.Event
createTextNode(data JS.String) JS.Text
elementFromPoint(x JS.Number, y JS.Number) ?JS.Element
elementsFromPoint(x JS.Number, y JS.Number) JS.Array
execCommand(commandId JS.String, showUI JS.Boolean, value JS.String) JS.Boolean
hasFocus() JS.Boolean
open(url JS.String, name JS.String, features JS.String) ?WindowProxy
queryCommandEnabled(commandId JS.String) JS.Boolean
queryCommandIndeterm(commandId JS.String) JS.Boolean
queryCommandState(commandId JS.String) JS.String
write(text ...JS.Any)
writeln(text ...JS.Any)
mut:
bgColor JS.String
fgColor JS.String
body JS.HTMLElement
cookie JS.String
domain JS.String
designMode JS.String
dir JS.String
vlinkColor JS.String
}
pub fn document_url(doc JS.Document) JS.String {
mut url := JS.String{}
#url = doc.URL;
return url
}
pub interface JS.Element {
JS.Node
classList JS.DOMTokenList
clientHeight JS.Number
clientLeft JS.Number
clientTop JS.Number
clientWidth JS.Number
localName JS.String
namespaceURI JS.String
ownerDocument JS.Document
part JS.DOMTokenList
prefix JS.String
scrollHeight JS.Number
scrollWidth JS.Number
tagName JS.String
closest(selector JS.String) ?JS.Element
getAttribute(qualifiedName JS.String) ?JS.String
getAttributeNS(namespace JS.String, localName JS.String) ?JS.String
getAttributeNames() JS.Array
getClientRects() JS.DOMRectList
getBoundingClientRect() JS.DOMRect
scrollTo(x JS.Number, y JS.Number)
scroll(x JS.Number, y JS.Number)
scrollBy(x JS.Number, y JS.Number)
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:
className JS.String
id JS.String
onfullscreenchange fn (this JS.Element, ev JS.Event) JS.Any
onfullscreenerror fn (this JS.Element, ev JS.Event) JS.Any
outerHTML JS.String
scrollLeft JS.Number
scrollTop JS.Number
slot JS.String
}
pub const (
document = JS.Document{}
)
pub fn window() JS.Window {
mut x := JS.Any(voidptr(0))
#x = window;
return x
}
fn init() {
#js__dom__document = document;
}
pub type EventCallback = fn (JS.Event)
// event_listener returns proper listener callback. This function is useful when you need access to `this` value
// that is EventTarget. When you need access only to Event itself you can just use `fn (JS.Event)` as listener.
pub fn event_listener(callback fn (JS.EventTarget, JS.Event)) EventCallback {
return fn [callback] (event JS.Event) {
mut target := JS.EventTarget(voidptr(0))
#target = this;
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 type OnDeviceMotion = fn (ev JS.DeviceMotionEvent) JS.Any
pub type OnDeviceOrientation = fn (ev JS.DeviceOrientationEvent) JS.Any
pub fn on_device_motion(cb fn (win JS.Window, ev JS.DeviceMotionEvent) JS.Any) OnDeviceMotion {
clos := fn [cb] (ev JS.DeviceMotionEvent) JS.Any {
mut win := JS.Any(voidptr(0))
#win = this;
return cb(win, ev)
}
return clos
}
pub fn on_device_orientation(cb fn (win JS.Window, ev JS.DeviceOrientationEvent) JS.Any) OnDeviceOrientation {
clos := fn [cb] (ev JS.DeviceOrientationEvent) JS.Any {
mut win := JS.Any(voidptr(0))
#win = this;
return cb(win, ev)
}
return clos
}
pub type AnimationFrameCallback = fn (JS.Number)
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
outerHeight JS.Number
outerWidth JS.Number
screenLeft JS.Number
screenTop JS.Number
screenX JS.Number
screenY JS.Number
scrollX JS.Number
scrollY JS.Number
alert(message JS.Any)
blur()
cancelIdleCallback(handle JS.Number)
captureEvents()
close()
confirm(message JS.String) JS.Boolean
focus()
moveBy(x JS.Number, y JS.Number)
moveTo(x JS.Number, y JS.Number)
print()
prompt(message JS.String, default_ JS.String) ?JS.String
stop()
resizeBy(x JS.Number, y JS.Number)
resizeTo(width JS.Number, height JS.Number)
scroll(x JS.Number, y JS.Number)
scrollBy(x JS.Number, y JS.Number)
scrollTo(x JS.Number, y JS.Number)
requestAnimationFrame(callback AnimationFrameCallback)
mut:
name string
opener JS.Any
ondevicemotion OnDeviceMotion
ondeviceorientation OnDeviceOrientation
}
pub interface JS.Path2D {}
pub struct JS.DeviceMotionEventAcceleration {
x JS.Number
y JS.Number
z JS.Number
}
pub struct JS.DeviceMotionEventRotationRate {
alpha JS.Number
beta JS.Number
gamma JS.Number
}
pub interface JS.DeviceMotionEvent {
JS.Event
interval JS.Number
acceleration JS.DeviceMotionEventAcceleration
accelerationIncludingGravity JS.DeviceMotionEventAcceleration
rotationRate JS.DeviceMotionEventRotationRate
}
pub interface JS.DeviceOrientationEvent {
JS.Event
absolute JS.Boolean
alpha JS.Number
beta JS.Number
gamma JS.Number
}
pub interface JS.DocumentType {
JS.Node
JS.ChildNode
name JS.String
ownerDocument JS.Document
publicId JS.String
systemId JS.String
}
[single_impl]
pub interface JS.WebGLProgram {}
[single_impl]
pub interface JS.WebGLShader {}
[single_impl]
pub interface JS.WebGLBuffer {}
[single_impl]
pub interface JS.WebGLFramebuffer {}
[single_impl]
pub interface JS.WebGLRenderbuffer {}
[single_impl]
pub interface JS.WebGLTexture {}
[single_impl]
pub interface JS.WebGLUniformLocation {}
[single_impl]
pub interface JS.WebGLVertexArrayObject {}
pub interface JS.WebGLRenderingContext {
canvas JS.HTMLCanvasElement
drawingBufferHeight JS.Number
drawingBufferWidth JS.Number
activeTexture(texture JS.Number)
attachShader(program JS.WebGLProgram, shader JS.WebGLProgram)
linkProgram(program JS.WebGLProgram)
bindAttribLocation(program JS.WebGLProgram, index JS.Number, name JS.String)
bindBuffer(target JS.Number, buffer JS.WebGLBuffer)
bindFramebuffer(target JS.Number, buffer JS.WebGLFrameBuffer)
bindRenderbuffer(target JS.Number, renderbuffer JS.WebGLRenderbuffer)
bindTexture(target JS.Number, texture JS.WebGLTexture)
clear(mask JS.Number)
clearColor(red JS.Number, green JS.Number, blue JS.Number, alpha JS.Number)
clearDepth(depth JS.Number)
clearStencil(s JS.Number)
colorMask(red JS.Boolean, green JS.Boolean, blue JS.Boolean, alpha JS.Boolean)
compileShader(shader JS.WebGLShader)
createBuffer() ?JS.WebGLBuffer
createFramebuffer() ?JS.WebGLFrameBuffer
createProgram() ?JS.WebGLProgram
createRenderbuffer() ?JS.WebGLRenderbuffer
createShader(typ JS.Number) ?JS.WebGLShader
createTexture() ?JS.WebGLTexture
cullFace(mode JS.Number)
deleteBuffer(buffer JS.WebGLBuffer)
deleteFramebuffer(buffer JS.WebGLFrameBuffer)
deleteProgram(program JS.WebGLProgram)
deleteRenderbuffer(buffer JS.WebGLRenderbuffer)
deleteShader(shader JS.WebGLShader)
deleteTexture(texture JS.WebGLTexture)
depthFunc(func JS.Number)
depthMask(flag JS.Boolean)
depthRange(zNear JS.Number, zFar JS.Number)
detachShader(program JS.WebGLProgram, shader JS.WebGLShader)
disable(cap JS.Number)
disableVertexAttribArray(index JS.Number)
drawArrays(mode JS.Number, first JS.Number, count JS.Number)
drawElements(mode JS.Number, count JS.Number, typ JS.Number, offset JS.Number)
enable(cap JS.Number)
enableVertexAttribArray(index JS.Number)
finish()
flush()
framebufferRenderbuffer(target JS.Number, attachment JS.Number, renderbuffertarget JS.Number, renderbuffer JS.WebGLRenderbuffer)
framebufferTexture2D(target JS.Number, attachment JS.Number, textarget JS.Number, texture JS.WebGLTexture, level JS.Number)
frontFace(mode JS.Number)
generateMipmap(target JS.Number)
getError() JS.Number
getExtension(name JS.String) JS.Any
getParameter(name JS.Number) JS.Any
getProgramParameter(program JS.WebGLProgram, pname JS.Number) JS.Any
getShaderSource(shader JS.WebGLShader) ?JS.String
bufferData(target JS.Number, data JS.TypedArray, usage JS.Number)
shaderSource(shader JS.WebGLShader, source JS.String)
getShaderParameter(shader JS.WebGLShader, pname JS.Number) JS.Any
vertexAttribPointer(index JS.Number, size JS.Number, typ JS.Number, normalized JS.Boolean, stride JS.Number, offset JS.Number)
getAttribLocation(program JS.WebGLProgram, name JS.String) JS.Number
useProgram(program JS.WebGLProgram)
getUniformLocation(program JS.WebGLProgram, name JS.String) ?JS.WebGLUniformLocation
uniformMatrix2fv(location JS.WebGLUniformLocation, transpose JS.Boolean, value JS.Array)
uniformMatrix3fv(location JS.WebGLUniformLocation, transpose JS.Boolean, value JS.Array)
uniformMatrix4fv(location JS.WebGLUniformLocation, transpose JS.Boolean, value JS.Array)
getProgramInfoLog(program JS.WebGLProgram) JS.String
getShaderInfoLog(shader JS.WebGLShader) JS.String
viewport(x JS.Number, y JS.Number, width JS.Number, height JS.Number)
scissor(x JS.Number, y JS.Number, width JS.Number, height JS.Number)
stencilFunc(func JS.Number, ref JS.Number, mask JS.Number)
stencilFuncSeparate(face JS.Number, func JS.Number, ref JS.Number, mask JS.Number)
stencilMask(mask JS.Number)
stencilMaskSeparate(face JS.Number, mask JS.Number)
stencilOp(fail JS.Number, zfail JS.Number, zpass JS.Number)
stencilOpSeparate(face JS.Number, fail JS.Number, zfail JS.Number, zpass JS.Number)
texParameterf(target JS.Number, pname JS.Number, param JS.Number)
texParameteri(target JS.Number, pname JS.Number, param JS.Number)
uniform1f(location JS.WebGLUniformLocation, x JS.Number)
uniform1i(location JS.WebGLUniformLocation, x JS.Number)
uniform2f(location JS.WebGLUniformLocation, x JS.Number, y JS.Number)
uniform2i(location JS.WebGLUniformLocation, x JS.Number, y JS.Number)
uniform3f(location JS.WebGLUniformLocation, x JS.Number, y JS.Number, z JS.Number)
uniform3i(location JS.WebGLUniformLocation, x JS.Number, y JS.Number, z JS.Number)
uniform4f(location JS.WebGLUniformLocation, x JS.Number, y JS.Number, z JS.Number, w JS.Number)
uniform4i(location JS.WebGLUniformLocation, x JS.Number, y JS.Number, z JS.Number, w JS.Number)
validateProgram(program JS.WebGLProgram)
vertexAttrib1f(index JS.Number, x JS.Number)
vertexAttrib1fv(index JS.Number, values JS.Array)
vertexAttrib2f(index JS.Number, x JS.Number, y JS.Number)
vertexAttrib2fv(index JS.Number, x JS.Number, y JS.Number, values JS.Array)
vertexAttrib3f(index JS.Number, x JS.Number, y JS.Number, z JS.Number)
vertexAttrib3fv(index JS.Number, x JS.Number, y JS.Number, z JS.Number, values JS.Array)
vertexAttrib4f(index JS.Number, x JS.Number, y JS.Number, z JS.Number, w JS.Number)
vertexAttrib4fv(index JS.Number, x JS.Number, y JS.Number, z JS.Number, w JS.Number, values JS.Array)
bufferSubData(target JS.Number, offset JS.Number, data JS.TypedArray)
compressedTexImage2D(target JS.Number, level JS.Number, internalformat JS.Number, width JS.Number, height JS.Number, border JS.Number, data JS.TypedArray)
compressedTexSubImage2D(target JS.Number, level JS.Number, xoffset JS.Number, yoffset JS.Number, width JS.Number, height JS.Number, format JS.Number, data JS.TypedArray)
readPixels(x JS.Number, y JS.Number, width JS.Number, height JS.Number, format JS.Number, typ JS.Number, border JS.Number, pixels JS.TypedArray)
texImage2D(target JS.Number, level JS.Number, internalformat JS.Number, format JS.Number, source JS.Node)
}
pub interface JS.WebGL2RenderingContext {
JS.WebGLRenderingContext
}
pub fn gl_vertex_shader() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.VERTEX_SHADER;
return num
}
pub fn gl_fragment_shader() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.FRAGMENT_SHADER;
return num
}
pub fn gl_element_array_buffer() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.ELEMENT_ARRAY_BUFFER;
return num
}
pub fn gl_array_buffer() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.ARRAY_BUFFER;
return num
}
pub fn gl_color_buffer_bit() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.COLOR_BUFFER_BIT;
return num
}
pub fn gl_depth_buffer_bit() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.COLOR_BUFFER_BIT;
return num
}
pub fn gl_triangles() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.TRIANGLES;
return num
}
pub fn gl_unsigned_short() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.UNSIGNED_SHORT;
return num
}
pub fn gl_static_draw() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.STATIC_DRAW;
return num
}
pub fn gl_link_status() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.LINK_STATUS;
return num
}
pub fn gl_compile_status() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.COMPILE_STATUS;
return num
}
pub fn gl_float() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.FLOAT;
return num
}
pub fn gl_depth_test() JS.Number {
mut num := JS.Number{}
#num = WebGLRenderingContext.DEPTH_TEST;
return num
}
// Event is an event which takes place in the DOM.
pub interface JS.Event {
JS.EventTarget
bubbles JS.Boolean
cancelable JS.Boolean
composed JS.Boolean
currentTarget JS.EventTarget
defaultPrevented JS.Boolean
eventPhase JS.Number
isTrusted JS.Boolean
srcElement JS.EventTarget
timeStamp JS.DOMHighResTimeStamp // composedPath returns the invocation target objects of event's path.
composedPath() JS.Array
initEvent(typ JS.String, bubbles JS.Boolean, cancelable JS.Boolean)
preventDefault()
stopImmediatePropagation()
stopPropagation()
mut:
returnValue JS.Boolean
}
pub fn event_type(ev JS.Event) string {
res := ''
#res.str = ev.type;
return res
}
pub fn create_event(typ string, bubbles bool, cancelable bool, composed bool) JS.Event {
mut ev := JS.Event(voidptr(0))
#ev = new Event(typ.str,bubbles.val,cancelable.val,composed.val);
return ev
}
pub interface JS.ErrorEvent {
JS.Event
colno JS.Number
error JS.Number
filename JS.Number
lineno JS.Number
message JS.String
}
[use_new]
pub fn JS.ErrorEvent.prototype.constructor(typ JS.String) JS.ErrorEvent
pub interface JS.UIEvent {
JS.Event
detail JS.Number
view JS.Any
}
[use_new]
pub fn JS.UIEvent.prototype.constructor(typ JS.String, dict JS.UIEventDict) JS.UIEvent
pub struct JS.EventInit {
bubbles JS.Boolean
cancelable JS.Boolean
composed JS.Boolean
}
pub struct JS.UIEventInitDict {
bubbles JS.Boolean
cancelable JS.Boolean
composed JS.Boolean
detail JS.Number
view JS.Any
which JS.Number
}
pub interface JS.MouseEvent {
JS.UIEvent
altKey JS.Boolean
button JS.Number
buttons JS.Number
clientX JS.Number
clientY JS.Number
ctrlKey JS.Number
metaKey JS.Number
movementX JS.Number
movementY JS.Number
offsetX JS.Number
offsetY JS.Number
pageX JS.Number
pageY JS.Number
relatedTarget JS.Any
screenX JS.Number
screenY JS.Number
shiftKey JS.Boolean
x JS.Number
y JS.Number
getModifierState(keyArg JS.String) JS.Boolean
}
pub interface JS.PointerEvent {
JS.MouseEvent
height JS.Number
isPrimary JS.Boolean
pointerId JS.Number
pointerType JS.String
pressure JS.Number
tangentialPressure JS.Number
tiltX JS.Number
tiltY JS.Number
twist JS.Number
width JS.Number
getCoalescedEvents() JS.Array
getPredictedEvents() JS.Array
}
pub interface JS.Gamepad {
axes JS.Array // Array<number>
buttons JS.Array // Array<GamepadButton>
connected JS.Boolean
hapticActuators JS.Array // Array<GamepadHapticActuator>
id JS.String
index JS.Number
mapping JS.String
timestamp JS.Number
}
[single_impl]
pub interface JS.GamepadButton {
pressed JS.Boolean
touched JS.Boolean
value JS.Number
}
[single_impl]
pub interface JS.GamepadHapticActuator {
}
pub interface JS.GamepadEvent {
JS.Event
gamepad JS.Gamepad
}
pub interface JS.HashChangeEvent {
JS.Event
newURL JS.String
oldURL JS.String
}
pub interface JS.MessageEvent {
JS.Event
data JS.Any
lastEventId JS.String
origin JS.String
ports JS.Array
source JS.Any
}
pub interface JS.MessagePort {
JS.EventTarget
close()
portMessage(message JS.Any, transfer JS.Array)
start()
}
pub interface JS.PageTransitionEvent {
JS.Event
persisted JS.Boolean
}
pub interface JS.PopStateEvent {
JS.Event
state JS.Any
}
pub interface JS.ProgressEvent {
lenghtComputable JS.Boolean
loaded JS.Number
target JS.Any
total JS.Number
}

View File

@ -0,0 +1,2 @@
// DOM API wrapper
module dom

3
vlib/js/js.v 100644
View File

@ -0,0 +1,3 @@
// Module containing various JS APIs wrappers.
module js

View File

@ -0,0 +1,79 @@
module promise
pub interface JS.Promise {
then(onFullfilled JS.Any, onRejected JS.Any)
catch(onCatch JS.Any) JS.Promise
finally(callback JS.Any) JS.Promise
}
[use_new]
pub fn JS.Promise.prototype.constructor(JS.Any) JS.Promise
pub fn JS.Promise.reject(JS.Any) JS.Promise
pub fn JS.Promise.resolve(JS.Any) JS.Promise
pub fn JS.Promise.race(JS.Array) JS.Promise
// The Promise object represents the eventual completion (or failure)
// of an asynchronous operation and its resulting value.
pub struct Promise<T, E> {
mut:
promise JS.Promise [noinit]
}
pub fn new<T, E>(executor fn (resolve fn (T), reject fn (E))) Promise<T, E> {
promise := JS.Promise.prototype.constructor(executor)
return Promise<T, E>{promise}
}
pub fn (p Promise<T, E>) then(on_fullfilled fn (T), on_rejected fn (E)) {
p.promise.then(on_fullfilled, on_rejected)
}
// catch method returns a Promise and deals with rejected cases only.
pub fn (p Promise<T, E>) catch(callback fn (error JS.Any)) Promise<T, E> {
promise := p.promise.catch(callback)
return Promise<T, E>{promise}
}
pub fn (p Promise<T, E>) finally(callback fn ()) Promise<int, int> {
promise := p.promise.finally(callback)
return Promise<int, int>{promise}
}
// reject<E> returns promise which was rejected because of specified error
pub fn reject<E>(error E) Promise<int, E> {
promise := JS.Promise.reject(error)
return Promise<int, E>{promise}
}
// resolve<E> returns promise which was resolved with specified value
pub fn resolve<T>(result T) Promise<T, int> {
promise := JS.Promise.resolve(error)
return Promise<T, int>{promise}
}
// race returns returns a promise that fulfills or rejects as soon as one of
// the promises in an iterable fulfills or rejects, with the value or reason from that promise.
pub fn race<T, E>(promises []Promise<T, E>) Promise<T, E> {
promises_ := JS.Array.prototype.constructor()
for elem in promises {
promises_.push(elem.promise)
}
promise := JS.Promise.race(promises_)
return Promise<T, E>{promise}
}
pub fn JS.Promise.all(JS.Array) JS.Promise
pub fn JS.Promise.allSettled(JS.Array) JS.Promise
/*
// all takes an iterable of promises as an input, and returns a single Promise that resolves to an array of
// the results of the input promises
pub fn all(array []JS.Promise) Promise<JS.Array, JS.Any> {
mut promise := JS.Promise(JS.Any(voidptr(0)))
#promise = Promise.all(array.arr.arr);
return Promise<Array,Any>{promise}
}
*/

View File

@ -0,0 +1,3 @@
// Promise API wrapper
module promise

View File

@ -0,0 +1,16 @@
fn test_promise() {
// TODO: For some reason compiler errors: "error: unknown function: js.promise.new", fix this
/*
p := promise.new<int, f64>(fn (resolve_ fn (x int), reject_ fn (x f64)) {
println('Promise code')
assert true
resolve_(42)
})
p.then(fn (val int) {
println('resolved')
assert val == 42
}, fn (fail f64) {
println('rejected')
assert false
})*/
}

View File

@ -194,14 +194,16 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
g.get_str_fn(rec_type)
}
mut unwrapped_rec_type := node.receiver_type
if g.table.cur_fn.generic_names.len > 0 {
if g.fn_decl != 0 && g.fn_decl.generic_names.len > 0 { // in generic fn
unwrapped_rec_type = g.unwrap_generic(node.receiver_type)
} else {
} else { // in non-generic fn
sym := g.table.get_type_symbol(node.receiver_type)
match sym.info {
ast.Struct, ast.Interface, ast.SumType {
generic_names := sym.info.generic_types.map(g.table.get_type_symbol(it).name)
if utyp := g.table.resolve_generic_to_concrete(node.receiver_type, generic_names,
// see comment at top of vlib/v/gen/c/utils.v
mut muttable := unsafe { &ast.Table(g.table) }
if utyp := muttable.resolve_generic_to_concrete(node.receiver_type, generic_names,
sym.info.concrete_types)
{
unwrapped_rec_type = utyp
@ -296,7 +298,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
}
mut name := util.no_dots('${receiver_type_name}_$node.name')
name = g.generic_fn_name(node.concrete_types, name, false)
// name = g.generic_fn_name(node.concrete_types, name, false)
g.write('${name}(')
g.expr(it.left)
g.gen_deref_ptr(it.left_type)
@ -539,6 +541,21 @@ fn (mut g JsGen) generic_fn_name(types []ast.Type, before string, is_decl bool)
}
fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
node := it
if node.generic_names.len > 0 && g.cur_concrete_types.len == 0 { // need the cur_concrete_type check to avoid inf. recursion
// loop thru each generic type and generate a function
for concrete_types in g.table.fn_generic_types[node.name] {
if g.pref.is_verbose {
syms := concrete_types.map(g.table.get_type_symbol(it))
the_type := syms.map(it.name).join(', ')
println('gen fn `$node.name` for type `$the_type`')
}
g.cur_concrete_types = concrete_types
g.gen_method_decl(node, typ)
}
g.cur_concrete_types = []
return
}
cur_fn_decl := g.fn_decl
unsafe {
g.fn_decl = &it
@ -550,22 +567,17 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) {
unsafe {
g.table.cur_fn = &it
}
node := it
mut name := it.name
if name in ['+', '-', '*', '/', '%', '<', '=='] {
name = util.replace_op(name)
}
if node.is_method {
unwrapped_rec_sym := g.table.get_type_symbol(g.unwrap_generic(node.receiver.typ))
if unwrapped_rec_sym.kind == .placeholder {
return
}
name = g.cc_type(node.receiver.typ, false) + '_' + name
}
name = g.js_name(name)
name = g.generic_fn_name(g.table.cur_concrete_types, name, true)
// name = g.generic_fn_name(g.table.cur_concrete_types, name, true)
if name in parser.builtin_functions {
name = 'builtin__$name'
}

View File

@ -85,6 +85,7 @@ mut:
sourcemap &sourcemap.SourceMap // maps lines in generated javascrip file to original source files and line
comptime_var_type_map map[string]ast.Type
defer_ifdef string
cur_concrete_types []ast.Type
out strings.Builder = strings.new_builder(128)
array_sort_fn map[string]bool
wasm_export map[string][]string
@ -1012,15 +1013,12 @@ fn (mut g JsGen) expr(node ast.Expr) {
g.gen_string_literal(node)
}
ast.StructInit {
// TODO: once generic fns/unwrap_generic is implemented
// if node.unresolved {
// g.expr(ast.resolve_init(node, g.unwrap_generic(node.typ), g.table))
// } else {
// // `user := User{name: 'Bob'}`
// g.gen_struct_init(node)
// }
// `user := User{name: 'Bob'}`
g.gen_struct_init(node)
if node.unresolved {
resolved := ast.resolve_init(node, g.unwrap_generic(node.typ), g.table)
g.expr(resolved)
} else {
g.gen_struct_init(node)
}
}
ast.TypeNode {
typ := g.unwrap_generic(node.typ)
@ -1262,8 +1260,9 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
continue
}
}
mut styp := g.typ(stmt.left_types[i])
l_sym := g.table.get_type_symbol(stmt.left_types[i])
mut styp := if stmt.left_types.len > i { g.typ(stmt.left_types[i]) } else { '' }
// l_sym := g.table.get_type_symbol(stmt.left_types[i])
if !g.inside_loop && styp.len > 0 {
g.doc.gen_typ(styp)
}
@ -1324,6 +1323,7 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
if is_assign && array_set {
g.write('new ${styp}(')
g.expr(left)
l_sym := g.table.get_type_symbol(stmt.left_types[i])
if l_sym.kind == .string {
g.write('.str')
} else {
@ -1366,11 +1366,13 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
}
}
} else if is_assign && !array_set {
l_sym := g.table.get_type_symbol(stmt.left_types[i])
if l_sym.kind == .string {
g.write('.str')
} else {
g.write('.val')
}
if !array_set {
g.write(' = ')
}
@ -1418,9 +1420,13 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt, semicolon bool) {
}
}
// TODO: Multiple types??
should_cast :=
should_cast := if stmt.left_types.len == 0 {
false
} else {
(g.table.type_kind(stmt.left_types.first()) in js.shallow_equatables)
&& (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last())
&& (g.cast_stack.len <= 0 || stmt.left_types.first() != g.cast_stack.last())
}
if should_cast {
g.cast_stack << stmt.left_types.first()
@ -1538,7 +1544,7 @@ fn (mut g JsGen) gen_expr_stmt_no_semi(it ast.ExprStmt) {
// cc_type whether to prefix 'struct' or not (C__Foo -> struct Foo)
fn (mut g JsGen) cc_type(typ ast.Type, is_prefix_struct bool) string {
sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut styp := sym.cname
mut styp := sym.cname.replace('>', '').replace('<', '')
match mut sym.info {
ast.Struct, ast.Interface, ast.SumType {
if sym.info.is_generic {
@ -3231,7 +3237,9 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
}
g.inc_indent()
for i, field in it.fields {
g.write('$field.name: ')
if field.name.len != 0 {
g.write('$field.name: ')
}
g.expr(field.expr)
if i < it.fields.len - 1 {
g.write(',')
@ -3461,8 +3469,20 @@ fn (mut g JsGen) gen_float_literal_expr(it ast.FloatLiteral) {
fn (mut g JsGen) unwrap_generic(typ ast.Type) ast.Type {
if typ.has_flag(.generic) {
if t_typ := g.table.resolve_generic_to_concrete(typ, g.table.cur_fn.generic_names,
g.table.cur_concrete_types)
/*
resolve_generic_to_concrete should not mutate the table.
It mutates if the generic type is for example []T and the
concrete type is an array type that has not been registered
yet. This should have already happened in the checker, since
it also calls resolve_generic_to_concrete. g.table is made
non-mut to make sure no one else can accidentally mutates the table.
*/
mut muttable := unsafe { &ast.Table(g.table) }
if t_typ := muttable.resolve_generic_to_concrete(typ, if g.fn_decl != 0 {
g.fn_decl.generic_names
} else {
[]string{}
}, g.cur_concrete_types)
{
return t_typ
}