Deprecate asm stmt for js target (#23149)

why ?

- We already have an emit that does the same thing
- The name asm itself is a bit confusing, you might think it's an alias
for asm.js or something else.
- The asm keyword is used differently on different compiler targets (it
makes it inexpressive).
- Does anyone (other than some compiler libraries) use asm instead of
emit ? If yes, it's a bit strange to use asm somewhere and emit
somewhere. By making the asm keyword for js target deprecated, there
would be even less use of the asm keyword for js target, reducing the
amount of confusion.
- New users might accidentally use a non-universal approach via the asm
keyword instead of emit, and then when they learn about asm, try to
figure out what the differences are.

see https://forum.nim-lang.org/t/10821

---------

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
ASVIEST
2024-01-02 09:49:54 +03:00
committed by GitHub
parent c7d742e484
commit 20d79c9fb0
11 changed files with 121 additions and 114 deletions

View File

@@ -1136,10 +1136,14 @@ proc genBreakStmt(p: PProc, n: PNode) =
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
lineF(p, "break Label$1;$n", [rope(p.blocks[idx].id)])
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
proc genAsmOrEmitStmt(p: PProc, n: PNode; isAsmStmt = false) =
genLineDir(p, n)
p.body.add p.indentLine("")
for i in 0..<n.len:
let offset =
if isAsmStmt: 1 # first son is pragmas
else: 0
for i in offset..<n.len:
let it = n[i]
case it.kind
of nkStrLit..nkTripleStrLit:
@@ -2981,7 +2985,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
genLineDir(p, n)
gen(p, n[0], r)
r.res = "var _ = " & r.res
of nkAsmStmt: genAsmOrEmitStmt(p, n)
of nkAsmStmt:
warningDeprecated(p.config, n.info, "'asm' for the JS target is deprecated, use the 'emit' pragma")
genAsmOrEmitStmt(p, n, true)
of nkTryStmt, nkHiddenTryStmt: genTry(p, n, r)
of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIncludeStmt,

View File

@@ -243,7 +243,7 @@ since (1, 5, 1):
else:
type A = impl(onSuccess(default(T)))
var ret: A
asm "`ret` = `future`.then(`onSuccess`, `onReject`)"
{.emit: "`ret` = `future`.then(`onSuccess`, `onReject`)".}
return ret
proc catch*[T](future: Future[T], onReject: OnReject): Future[void] =
@@ -266,4 +266,4 @@ since (1, 5, 1):
discard main()
asm "`result` = `future`.catch(`onReject`)"
{.emit: "`result` = `future`.catch(`onReject`)".}

View File

@@ -58,7 +58,7 @@ func contains*(pattern: cstring; self: RegExp): bool =
assert jsregex in r"abc"
assert jsregex notin r"abcd"
assert "xabc".contains jsregex
asm "`result` = `self`.test(`pattern`);"
{.emit: "`result` = `self`.test(`pattern`);".}
func startsWith*(pattern: cstring; self: RegExp): bool =
## Tests if string starts with given RegExp

View File

@@ -190,7 +190,7 @@ proc hashData*(data: pointer, size: int): Hash =
var h: Hash = 0
when defined(js):
var p: cstring
asm """`p` = `Data`"""
{.emit: """`p` = `Data`""".}
else:
var p = cast[cstring](data)
var i = 0
@@ -217,7 +217,7 @@ else:
when defined(js):
var objectID = 0
proc getObjectId(x: pointer): int =
asm """
{.emit: """
if (typeof `x` == "object") {
if ("_NimID" in `x`)
`result` = `x`["_NimID"];
@@ -226,7 +226,7 @@ when defined(js):
`x`["_NimID"] = `result`;
}
}
"""
""".}
proc hash*(x: pointer): Hash {.inline.} =
## Efficient `hash` overload.

View File

@@ -991,9 +991,9 @@ when defined(js):
else: assert false
proc len(x: JsObject): int =
asm """
{.emit: """
`result` = `x`.length;
"""
""".}
proc convertObject(x: JsObject): JsonNode =
var isRawNumber = false
@@ -1004,14 +1004,15 @@ when defined(js):
result.add(x[i].convertObject())
of JObject:
result = newJObject()
asm """for (var property in `x`) {
{.emit: """for (var property in `x`) {
if (`x`.hasOwnProperty(property)) {
"""
""".}
var nimProperty: cstring
var nimValue: JsObject
asm "`nimProperty` = property; `nimValue` = `x`[property];"
{.emit: "`nimProperty` = property; `nimValue` = `x`[property];".}
result[$nimProperty] = nimValue.convertObject()
asm "}}"
{.emit: "}}".}
of JInt:
result = newJInt(x.to(int))
of JFloat:

View File

@@ -219,13 +219,13 @@ when defined(js):
let a = newFloat64Array(buffer)
let b = newUint32Array(buffer)
a[0] = x
asm """
{.emit: """
function updateBit(num, bitPos, bitVal) {
return (num & ~(1 << bitPos)) | (bitVal << bitPos);
}
`b`[1] = updateBit(`b`[1], 31, `sgn`);
`result` = `a`[0]
"""
""".}
proc signbit*(x: SomeFloat): bool {.inline, since: (1, 5, 1).} =
## Returns true if `x` is negative, false otherwise.

View File

@@ -29,13 +29,13 @@ initLock(gFunsLock)
when defined(js):
proc addAtExit(quitProc: proc() {.noconv.}) =
when defined(nodejs):
asm """
{.emit: """
process.on('exit', `quitProc`);
"""
""".}
elif defined(js):
asm """
{.emit: """
window.onbeforeunload = `quitProc`;
"""
""".}
else:
proc addAtExit(quitProc: proc() {.noconv.}) {.
importc: "atexit", header: "<stdlib.h>".}
@@ -72,16 +72,16 @@ proc addExitProc*(cl: proc() {.noconv.}) =
when not defined(nimscript) and (not defined(js) or defined(nodejs)):
proc getProgramResult*(): int =
when defined(js) and defined(nodejs):
asm """
{.emit: """
`result` = process.exitCode;
"""
""".}
else:
result = programResult
proc setProgramResult*(a: int) =
when defined(js) and defined(nodejs):
asm """
{.emit: """
process.exitCode = `a`;
"""
""".}
else:
programResult = a

View File

@@ -104,7 +104,7 @@ when defined(js):
proc nimFloatToString(a: float): cstring =
## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
# print `-0.0` properly
asm """
{.emit: """
function nimOnlyDigitsOrMinus(n) {
return n.toString().match(/^-?\d+$/);
}
@@ -116,7 +116,7 @@ when defined(js):
`result` = `a`+".0"
}
}
"""
""".}
proc addFloat*(result: var string; x: float | float32) {.inline.} =
## Converts float to its string representation and appends it to `result`.

View File

@@ -1871,14 +1871,14 @@ when defined(js) or defined(nimdoc):
tmp.add(cstring("ab"))
tmp.add(cstring("cd"))
doAssert tmp == "abcd"
asm """
{.emit: """
if (`x` === null) { `x` = []; }
var off = `x`.length;
`x`.length += `y`.length;
for (var i = 0; i < `y`.length; ++i) {
`x`[off+i] = `y`.charCodeAt(i);
}
"""
""".}
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} =
## Appends `y` to `x` in place.
## Only implemented for JS backend.

View File

@@ -324,7 +324,7 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} =
return true
else:
var sameObject = false
asm """`sameObject` = `x` === `y`"""
{.emit: """`sameObject` = `x` === `y`""".}
if sameObject: return true
if x.len != y.len:

View File

@@ -49,7 +49,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} =
result[0] = x
proc isNimException(): bool {.asmNoStackFrame.} =
asm "return `lastJSError` && `lastJSError`.m_type;"
{.emit: "return `lastJSError` && `lastJSError`.m_type;".}
proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
if isNimException(): result = cast[ref Exception](lastJSError)
@@ -148,7 +148,7 @@ proc raiseException(e: ref Exception, ename: cstring) {.
unhandledException(e)
when NimStackTrace:
e.trace = rawWriteStackTrace()
asm "throw `e`;"
{.emit: "throw `e`;".}
proc reraiseException() {.compilerproc, asmNoStackFrame.} =
if lastJSError == nil:
@@ -158,7 +158,7 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} =
if isNimException():
unhandledException(cast[ref Exception](lastJSError))
asm "throw lastJSError;"
{.emit: "throw lastJSError;".}
proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} =
raise newException(OverflowDefect, "over- or underflow")
@@ -176,7 +176,7 @@ proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} =
raise newException(FieldDefect, formatFieldDefect(f, discVal))
proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = {};
for (var i = 0; i < arguments.length; ++i) {
var x = arguments[i];
@@ -189,7 +189,7 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
}
}
return result;
"""
""".}
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
{.emit: """
@@ -277,64 +277,64 @@ proc toJSStr(s: string): cstring {.compilerproc.} =
result = join(res)
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = new Array(`len`);
for (var i = 0; i < `len`; i++) {result[i] = 0;}
return result;
"""
""".}
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
# argument type is a fake
asm """
{.emit: """
var result = 0;
for (var elem in `a`) { ++result; }
return result;
"""
""".}
proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
for (var elem in `a`) { if (!`b`[elem]) return false; }
for (var elem in `b`) { if (!`a`[elem]) return false; }
return true;
"""
""".}
proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
for (var elem in `a`) { if (!`b`[elem]) return false; }
return true;
"""
""".}
proc SetLt(a, b: int): bool {.compilerproc.} =
result = SetLe(a, b) and not SetEq(a, b)
proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
var result = {};
for (var elem in `a`) {
if (`b`[elem]) { result[elem] = true; }
}
return result;
"""
""".}
proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
var result = {};
for (var elem in `a`) { result[elem] = true; }
for (var elem in `b`) { result[elem] = true; }
return result;
"""
""".}
proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
var result = {};
for (var elem in `a`) {
if (!`b`[elem]) { result[elem] = true; }
}
return result;
"""
""".}
proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`a` == `b`) return 0;
if (!`a`) return -1;
if (!`b`) return 1;
@@ -343,7 +343,7 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} =
if (result != 0) return result;
}
return `a`.length - `b`.length;
"""
""".}
proc cmp(x, y: string): int =
when nimvm:
@@ -354,7 +354,7 @@ proc cmp(x, y: string): int =
result = cmpStrings(x, y)
proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`a` == `b`) return true;
if (`a` === null && `b`.length == 0) return true;
if (`b` === null && `a`.length == 0) return true;
@@ -364,29 +364,29 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} =
for (var i = 0; i < alen; ++i)
if (`a`[i] != `b`[i]) return false;
return true;
"""
""".}
when defined(kwin):
proc rawEcho {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
var buf = "";
for (var i = 0; i < arguments.length; ++i) {
buf += `toJSStr`(arguments[i]);
}
print(buf);
"""
""".}
elif not defined(nimOldEcho):
proc ewriteln(x: cstring) = log(x)
proc rawEcho {.compilerproc, asmNoStackFrame.} =
asm """
{.emit: """
var buf = "";
for (var i = 0; i < arguments.length; ++i) {
buf += `toJSStr`(arguments[i]);
}
console.log(buf);
"""
""".}
else:
proc ewriteln(x: cstring) =
@@ -414,84 +414,84 @@ else:
# Arithmetic:
proc checkOverflowInt(a: int) {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`a` > 2147483647 || `a` < -2147483648) `raiseOverflow`();
"""
""".}
proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` + `b`;
`checkOverflowInt`(result);
return result;
"""
""".}
proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` - `b`;
`checkOverflowInt`(result);
return result;
"""
""".}
proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` * `b`;
`checkOverflowInt`(result);
return result;
"""
""".}
proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
return Math.trunc(`a` / `b`);
"""
""".}
proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
return Math.trunc(`a` % `b`);
"""
""".}
proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`();
"""
""".}
proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` + `b`;
`checkOverflowInt64`(result);
return result;
"""
""".}
proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` - `b`;
`checkOverflowInt64`(result);
return result;
"""
""".}
proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
var result = `a` * `b`;
`checkOverflowInt64`(result);
return result;
"""
""".}
proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`b` == 0n) `raiseDivByZero`();
if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`();
return `a` / `b`;
"""
""".}
proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
asm """
{.emit: """
if (`b` == 0n) `raiseDivByZero`();
if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`();
return `a` % `b`;
"""
""".}
proc negInt(a: int): int {.compilerproc.} =
result = a*(-1)
@@ -526,22 +526,22 @@ proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} =
case n.kind
of nkNone: sysAssert(false, "nimCopyAux")
of nkSlot:
asm """
{.emit: """
`dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
"""
""".}
of nkList:
asm """
{.emit: """
for (var i = 0; i < `n`.sons.length; i++) {
nimCopyAux(`dest`, `src`, `n`.sons[i]);
}
"""
""".}
of nkCase:
asm """
{.emit: """
`dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
for (var i = 0; i < `n`.sons.length; ++i) {
nimCopyAux(`dest`, `src`, `n`.sons[i][1]);
}
"""
""".}
proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
case ti.kind
@@ -549,9 +549,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
if not isFatPointer(ti):
result = src
else:
asm "`result` = [`src`[0], `src`[1]];"
{.emit: "`result` = [`src`[0], `src`[1]];".}
of tySet:
asm """
{.emit: """
if (`dest` === null || `dest` === undefined) {
`dest` = {};
}
@@ -560,18 +560,18 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
}
for (var key in `src`) { `dest`[key] = `src`[key]; }
`result` = `dest`;
"""
""".}
of tyTuple, tyObject:
if ti.base != nil: result = nimCopy(dest, src, ti.base)
elif ti.kind == tyObject:
asm "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;"
{.emit: "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;".}
else:
asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;"
{.emit: "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;".}
nimCopyAux(result, src, ti.node)
of tyArrayConstr, tyArray:
# In order to prevent a type change (TypedArray -> Array) and to have better copying performance,
# arrays constructors are considered separately
asm """
{.emit: """
if(ArrayBuffer.isView(`src`)) {
if(`dest` === null || `dest` === undefined || `dest`.length != `src`.length) {
`dest` = new `src`.constructor(`src`);
@@ -593,9 +593,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
}
}
}
"""
""".}
of tySequence, tyOpenArray:
asm """
{.emit: """
if (`src` === null) {
`result` = null;
}
@@ -608,55 +608,55 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
`result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base);
}
}
"""
""".}
of tyString:
asm """
{.emit: """
if (`src` !== null) {
`result` = `src`.slice(0);
}
"""
""".}
else:
result = src
proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
asm "`result` = null;"
{.emit: "`result` = null;".}
case ti.kind
of tyPtr, tyRef, tyVar, tyNil:
if isFatPointer(ti):
asm """
{.emit: """
`result` = [null, 0];
"""
""".}
of tySet:
asm """
{.emit: """
`result` = {};
"""
""".}
of tyTuple, tyObject:
if ti.kind == tyObject:
asm "`result` = {m_type: `ti`};"
{.emit: "`result` = {m_type: `ti`};".}
else:
asm "`result` = {};"
{.emit: "`result` = {};".}
of tySequence, tyOpenArray, tyString:
asm """
{.emit: """
`result` = [];
"""
""".}
of tyArrayConstr, tyArray:
asm """
{.emit: """
`result` = new Array(`x`.length);
for (var i = 0; i < `x`.length; ++i) {
`result`[i] = genericReset(`x`[i], `ti`.base);
}
"""
""".}
else:
discard
proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
asmNoStackFrame, compilerproc.} =
# types are fake
asm """
{.emit: """
var result = new Array(`len`);
for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
return result;
"""
""".}
proc chckIndx(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i
@@ -685,7 +685,7 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
return true
proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
asm "`x`.push(`c`);"
{.emit: "`x`.push(`c`);".}
{.pop.}
@@ -712,9 +712,9 @@ proc parseFloatNative(a: openarray[char]): float =
let cstr = cstring str
asm """
{.emit: """
`result` = Number(`cstr`);
"""
""".}
proc nimParseBiggestFloat(s: openarray[char], number: var BiggestFloat): int {.compilerproc.} =
var sign: bool