-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Transform usage example #14
Comments
@jnordberg See https://github.com/willemneal/visitor-as, it can help you. |
More transform that may serve as examples: |
Thanks for those references! I'm experimenting with implementing something akin to C++'s Attaching my transform that does this for posterity, it's super unsafe easy to break but works as a proof of concept, I think it could be made safe by actually compiling the code into another wasm module that's executed by the transform and only allowing a safe set of instructions to be used in the body of functions marked with Example usage: // @ts-ignore: decorator
@staticEval
function hash(value: string): i32 {
let l = value.length, rv = 0
for (let i = 0; i < l; i++) {
rv = (rv << 5) - rv + value.charCodeAt(i)
}
return rv
}
function getString() {
return 'hello runtime!'
}
const hash1 = hash('hello') // i32.const 99162322
const hash2 = hash(getString()) // call $assembly/index/hash Transform: import {
Parser,
NodeKind,
FunctionDeclaration,
IdentifierExpression,
CallExpression,
Expression,
IntegerLiteralExpression,
LiteralExpression,
LiteralKind,
FloatLiteralExpression,
StringLiteralExpression,
} from 'assemblyscript'
import { SimpleParser, TransformVisitor } from 'visitor-as'
class StaticEvalTransform extends TransformVisitor {
staticFunctions: { [name: string]: Function } = {}
visitCallExpression(node: CallExpression): Expression {
if (node.expression instanceof IdentifierExpression) {
const fn = this.staticFunctions[node.expression.text]
// someone is calling a staticEval function
if (fn) {
// only allow constant as arguments
let args = node.args
.filter((arg) => arg.kind == NodeKind.LITERAL)
.map((value) => {
const arg = value as LiteralExpression
switch (arg.literalKind) {
case LiteralKind.INTEGER:
// yes this will explode :)
return parseInt(
(arg as IntegerLiteralExpression).value.toString()
)
case LiteralKind.FLOAT:
return parseFloat(
(arg as FloatLiteralExpression).value.toString()
)
case LiteralKind.STRING:
return (arg as StringLiteralExpression).value
}
})
.filter((arg) => arg !== undefined)
if (args.length === node.args.length) {
// call fn with args and inline the result
let result = fn(...args)
let res = SimpleParser.parseExpression(
JSON.stringify(result)
)
res.range = node.range
return res
}
}
}
return super.visitCallExpression(node)
}
afterParse(parser: Parser): void {
this.staticFunctions = {}
const sources = this.program.sources.filter((node) => !node.isLibrary)
// find all top-level staticEval functions
for (const source of sources) {
for (const statement of source.statements) {
if (statement instanceof FunctionDeclaration) {
let staticEval = statement.decorators?.some(
(decorator) =>
decorator.name.kind == NodeKind.IDENTIFIER &&
(<IdentifierExpression>decorator.name).text === 'staticEval'
)
if (!staticEval) continue
let params = statement.signature.parameters.map(
(param) => param.name.text
)
this.staticFunctions[statement.name.text] = Function(
...params,
statement.body.range.toString()
)
}
}
}
// visit all statements
this.visit(sources)
}
}
export = StaticEvalTransform |
Perhaps this is an interesting idea for implementing Partial Evaluation |
@dcodeIO Hi, Maybe Need a new example to show transform in typescript. |
It would be awesome to have a usage example for transforms that showed how to transform some code. I want to try implementing a custom decorator as a preprocessor macro (as hinted by the docs you can do) but I'm not sure where to start.
The text was updated successfully, but these errors were encountered: