Is there any way to get the source line number in Javascript, like __LINE__ for C or PHP?
There is a way, although more expensive: throw an exception, catch it immediately, and dig out the first entry from its stack trace. See example here on how to parse the trace. The same trick can also be used in plain Java (if the code is compiled with debugging information turned on).
Edit: Apparently not all browsers support this. The good news is (thanks for the comment, Christoph!) that some browsers export source file name and line number directly through the fileName and lineNumber properties of the error object.
The short answer is no.
The long answer is that depending on your browser you might be able to throw & catch an exception and pull out a stack trace.
I suspect you're using this for debugging (I hope so, anyway!) so your best bet would be to use Firebug. This will give you a console object; you can call console.trace() at any point to see what your programme is doing without breaking execution.
You can try to run C preprocessor (f.e. cpp from GNU Compiler Collection) on your javascript files -- either dynamically with each request or statically, by making this operation be applied every time you change your javascript files. I think the javascript syntax is similar enough for this to work.
Then you'd have all the power of C preprocessor.
You can use this in vanilla JS:
function getLine(offset) {
var stack = new Error().stack.split('\n'),
line = stack[(offset || 1) + 1].split(':');
return parseInt(line[line.length - 2], 10);
}
Object.defineProperty(window, '__LINE__', {
get: function () {
return getLine(2);
}
});
You will now have access to the global variable __LINE__
A __LINE__ in C is expanded by a preprocessor which literally replaces it with the line number of the current input. So, when you see
printf("Line Number: %d\r\n", __LINE__);
the compiler sees:
printf("Line Number: %d\r\n", 324);
In effect the number (324 in this case) is HARDCODED into the program. It is only this two-pass mechanism that makes this possible.
I do not know how PHP achieves this (is it preprocessed also?).
I think preprocessing makes more sense, in that it adds no runtime overhead. An alternative to the C preprocessor is using perl, as in the 2 step procedure below:
1 – add “Line # 999 \n” to each line in the script that you want numbered, e.g.,
alert ( "Line # 999 \n"+request.responseText);
2 – run the perl below:
cat my_js.js | perl -ane "{ s/Line # \d+ /Line # $. /; print $_;}" > C_my_js.js; mv C_my_js.js my_js.js
There is one workaround.
Usually the __ LINE __ combined with the __ FILE __ is used for marking a locations in code and the marking is done to find that location later.
However, it is possible to achieve the same effect by using Globally Unique Identifiers (GUID-s) in stead of the __ LINE __ and __ FILE __. Details of the solution reside in the COMMENTS.txt of a BSD-licensed toolset that automates the process.
Related
I've used microsoft's vscode for some months, but since 2 updates the indentation is broken for me, without a way to fix it. I therefore consider switching to atom. I was working with atom before, and never had this problem, but now it seems to have the same (wrong for me) behaviour as vscode:
if (xxx) // press enter here and type 'something();'
should result in
if (xxx)
something();
but it results in
if (xxx)
something();
It will work completely finde if you add { }, but without them its like the above.
How can I fix this in atom? The basic identation settings don't seem to cover this.
My way of doing this si to always use {} (also because I'm using linter-standard-js) That way, you type
if (myCondition) {}
When you return between the accolades, you get the following
if (myCondition) {
// indented and here you go
}
You can add extra conditions for Atom to change the indent level in your config.cson file, following the lead of the packages that define those conditions in the first place. Add the following to the top level of config.cson and Atom will automatically add a level of indentation after a line that matches the regular expression if\s*\(.*\)$. If you already have a .source.js entry, make sure to change that instead of just pasting this bit in.
'.source.js':
editor:
increaseIndentPattern: '(?x)
\\{ [^}"\']* $
| \\[ [^\\]"\']* $
| \\( [^)"\']* $
| if\\s*\\(.*\\)$
'
Ive got this labratory equipment that is connected to my PC. It uses special OCX file to communicate with the device (reading, setting parameters and such). I got this code from manual that seems to be working. I get a message box saying "Magnification =1272.814 Last error=API not initialized".
<HTML>
<HEAD>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub window_onLoad()
Dim Value
Dim er
call Api1.Initialise("")
call Api1.Get("AP_MAG",Value)
call Api1.GetLastError(er)
call window.alert("Magnification = " + CStr(Value)+"Last error="+er)
call Api1.ClosingControl()
end sub
-->
</SCRIPT>
<TITLE>New Page</TITLE>
</HEAD>
<BODY>
<object classid="CLSID:71BD42C4-EBD3-11D0-AB3A-444553540000" id="Api1">
<PARAM NAME="_Version" VALUE="65536">
<PARAM NAME="_ExtentX" VALUE="2096">
<PARAM NAME="_ExtentY" VALUE="1058">
<PARAM NAME="_StockProps" VALUE="0">
</OBJECT>
</BODY>
</HTML>
So because I have 0% knowledge in vbs and about 10% in jscript I`m trying to rewrite the same thing in Javascript. And I also have some necessary code already written in js.
<script language="JScript">
var Api1=new ActiveXObject("ApiCtrl");
var value;
var er;
Api1.Initialise("");
Api1.Get("AP_MAG",value);
Api1.GetLastError(er);
window.alert("Magnification = " + value+"\n Last error="+er);
Api1.ClosingControl();
</script>
Unfortunately I get a type mismatch error in either .Get or .GetLastError methods either with var value; var er; or var value=""; var er="";
Here is what API manual has to say
long GetLastError(VARIANT* Error)
[out] Error is the error string
associated with the error code for the last error
Remarks: This call will return a VT_BSTR VARIANT associated with the last error. Return
Value: If the call succeeds, it returns 0. If the call fails, an error
code is returned from the function.
long Get(LPCTSTR lpszParam, VARIANT* vValue)
[in] lpszParam is the name of the parameter e.g. “AP_MAG”
[in][out] vValue is the value of the parameter Remarks: This call will get the
value of the parameter specified and return it in vValue. In C++,
before calling this functions you have to specify the variant type
(vValue.vt) to either VT_R4 or VT_BSTR. If no variant type is defined
for vValue, it defaults to VT_R4 for analogue parameters (AP_XXXX) and
VT_BSTR for digital parameters (DP_XXXX). If the variant type is VT_R4
for an analogue parameter, then the floating point representation is
returned in the variant. If a VT_BSTR variant is passed, analogue
values are returned as scaled strings with the units appended (e.g.
AP_WD would return “= 10mm”). For digital parameters, VT_R4 variants
result in a state number and VT_BSTR variants result in a state string
(e.g. DP_RUNUPSTATE would return state 0 or “Shutdown” or the
equivalent in the language being supported). In C++, if the variant
type was specified as VT_BSTR then the API will internally allocate a
BSTR which the caller has to de-allocate using the SDK call
::SysFreeString (vValue.bstrVal)
Welcome to StackOverflow!
Well, each language is made with purpose. Then come to deal with ActiveX objects in browser (or WSH) environment, VBScript is the best choice, while JavaScript is most worst.
JavaScript hasn't so-called out parameters. That mean all function arguments are passed by value (as copy). Lets show you this with examples.
' VBScript
Dim X, Y
X = 1
Y = 2
Foo X, Y
MsgBox "Outer X = " & X & ", Y = " & Y
'> Local args: 6, 8
'> Outer X = 1, Y = 8
Sub Foo(ByVal arg1, ByRef arg2)
arg1 = 6
arg2 = 8
MsgBox "Local args: " & arg1 & ", " & arg2
End Sub
By default in VBS the arguments are passed by reference, so ByRef prefix in function arguments declaration is optional. I include it for clarity.
What the example illustrate is the meaning of "by reference" or "out" parameter. It behave like return value because it modify referenced variable. While modifying "by value" variable has no effect outside of the function scope, because we modify a "copy" of that variable.
// JavaScript
function foo(arg1) {
arg1 = 2;
alert('Local var = ' + arg1);
}
var x = 0;
foo(x);
alert('Outer var = ' + x);
// Local var = 2
// Outer var = 0
Now take a look at this thread. Looks like there is a kind of partial solution by using empty objects. I'm not sure in which cases that will work, but for sure it's very limited hack.
If this not help in your case, then looks like it's time to go with VBScript. Starting with VBS is easy anyway. It's the most user friendly language I ever touch. I was need days, even weeks with other languages only to get started, while just after a few hours with VBS I was able to use it freely.
[EDIT] Well, I made a lot more efforts to reply as may looks like at the glance :) Starting with the language limitation you met. Afterwards going to explain the nature of that limitation (what's "in/out" parameter), and the best way to do that is via example, and this is what I did. Afterwards I show you the only workaround out there to deal with this limitation in JS. Can we consider this as complete answer?
You not mention whether you test this "empty-object-trick", but as you still asking I presume you did that and it's not work with your OCX, right? Then, in this case, you're just forced to deal with your OCX via VBScript, what was my answer from the beginning. And as you prefer to stay with JS then you need to integrate a piece of VB code in your solution.
And as you noted too, this VBs/Js integration is a whole new question. Yes, good question of course, but it's a metter of new topic.
Ok, lets say that the question you append below: "why it should work with passing objects as a function parameter", is still a part of the main question. Well, as you see, even people using JS daily (am not one of them) has no idea what happens "behind the hood", i.e. do not expect an answer on what the JS-engine do in this case, or how this cheat the JS-engine to do something that it's not designed to do. Personally, as I use JS very rarely and not for such tasks, am not even sure if this trick works at all. But as the JS-guys assert it works (in some cases) then we s'd trust them. But that's all about. If this approach fail then it's not an option.
Now what's remain is a bit of homework, you s'd research all available methods for VBs/Js integration, also test them to see which one is most applicable to your domain, and if by chance you meet with difficulties, just then come-back to the forum with new topic and the concrete issue you're trying to resolve.
And to become as helpful as possible, I'll facilitate you with several references to get started.
Here is the plan...
1. If it's possible to work without VBs/Js integration then use stay-alone .VBS files (in WSH environment), else ...
2. In case you work in browser environment (HTML or HTA) then you can embed both (VBs/Js), and your integration w'd be simple.
3. Or may integrate VBs/Js with Windows Script Files (.wsf).
4. Or use ScriptControl that allow running VBScript from within JScript (or backward/opposite).
Links:
Using the ScriptControl
How To Call Functions Using the Script Control
An example VBs/Js integration using ScriptControl via
Batch-Embeded-Script
What is Batch-Embeded-Script:
VBS/Batch Hybrid
JS/Batch Hybrid
5. Some other method (if you find, that am not aware of).
Well, after all this improvements I not see what I can append more, and as I think, now
my answer is more than complete. If you agree with my answer then accept it by clicking on the big white arrow. Of course, if you expect to get better reply from other users, you may still wait, but keep in mind that unanswered questions stay active just for awhile and then become closed.
I am finding that LESS has a hobbled JavaScript evaluator, at least the way I am using it, which is to compile *.less files into *.css on a client before uploading them to the web server.
I'm aware that compilation may be more often done server-side, but for performance & simplicity we only want CSS files on the server. I'm compiling the LESS files on Fedora Linux with the lessc ruby gem installed into Node Package Manager as in these instructions.
The compiler is working perfectly, but as far as I can tell the JavaScript expression evaluation is sorely limited. I believe this also applies to server-side JavaScript expression evaluation based on this posting which suggests uncertainty about how the JavaScript engine is plugged into the LESS environment.
All I can use are simple, comma-separated expressions, like the following:
#bar: `
"ignored-string-expression"
,
5
`;
div.test-thing { content: ~"#{bar}"; }
which compiles into:
div.test-thing {
content: 5;
}
When I try to define a function, the compiler barfs (whether or not the semicolon in the expression is backslash-escaped):
[719] anjaneya% cat testfunc.less
#bar: `function foo() {return 5}; foo()`;
div.test-thing { content: ~"#{bar}"; }
[720] anjaneya% lessc testfunc.less
SyntaxError: JavaScript evaluation error: `function foo() {return 5}; foo()` ...
There also doesn't seem to be any way of looping, even if you try to trick it into evaluating a loop as you would the "ignored-string-expression" above, like:
#foo: `x = 0,
for (var n = 0; n <= 10; n++) { x++; },
x
`;
div.test-thing { content: ~"#{bar}"; }
which says:
ParseError: Syntax Error on line 1 ...
Why bother? To be able to compile this LESS:
#svgSource: '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><linearGradient id="g" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#{start}" /><stop offset="1" stop-color="#{end}" /></linearGradient><rect x="0" y="0" width="100%" height="100%" fill="url(#g)" /></svg>';
into this CSS:
background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZyIgeDE9IjAiIHkxPSIwIiB4Mj0iMCIgeTI9IjEiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iIzU3OWRkYiIgLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDAwMjIiIC8+PC9saW5lYXJHcmFkaWVudD48cmVjdCB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJ1cmwoI2cpIiAvPjwvc3ZnPg==);
using a program like this, whether the algorithm is implemented in JavaScript, PHP, Perl, UNIX shell, or anything else. This processing might be done without function definitions but not without looping, and without functions you can't even have recursion.
Given that both functions and looping are compound statements that probably aren't evaluated as expressions (it's not LISP), that is probably the basis for the failure... it's not really a full JavaScript interpreter. So I'm hoping someone who really knows the LESS compiler will:
clarify the limitation above, so I can use JavaScript & LESS portably for this task
say how this problem can be worked around (e.g., with a "shell escape" or any evaluation environment that can process strings iteratively) and/or
say how to extend the LESS compiler with such text processing capabilities, like a "real" JavaScript engine.
The data-uri() function is now built into LESS:
http://lesscss.org/functions/#misc-functions-data-uri
Will that help?
I think what you're looking for is both a mixture of a BUNCH of little frustrating things about using javascript in LESS.
All javascript has to be on one line. (I... don't even.. whatever.)
All javascript has to return something or you get the completely useless error "Cannot read property 'value' of undefined"
All javascript must be one statement. This comes from the original use case where they were thinking you would do something like #foo: ~'something.javascript.is.good.at({#bar});'
Number 1 is formatting, 2 just means you need to return something even if you don't use it, but number 3 catches a lot of people off guard. To get around it, just make you "one thing" a self-executing anonymous function.
Eg:
(function(){
do.some.cool.stuff();
other.cool.things();
return('Fry');
})();
So the LESS parser sees that (make sure it's all in one line instead of how I wrote it!), bundles it off to javascript land as a single execution, reads the return value, and calls it a day.
If you want to see it in action, I recently wrote LESS mixin to make RGBA 1x1 pixels for background fills, etc. that uses all of this madness.
Hope that helps!
I know this post is a couple of years old but javascript embedded in LESS can be very handy so I though I would post some tips:
//All javascript must
// a. be on the rhs of an assignment e.g. #x:` var x = #{val}+7`;
// b. must evaluate to a value
// c. cannot be terminated by a ';'
//
// To get around this, multiline code can be packed into an IIFE......
#val:7;
#loop:`(function(val){
var sum=0;
for(var i=0; i<val; i++){sum+=i;}
return sum;
} )(#{val})`;
.test{
content:#loop; // content: 21;
}
// console.log writes directly to the beginning of the output file
#x:`console.log('/*...... loop = #{loop}.......*/')`; // /*...... loop = 21.......*/
// you can use the global variable. Here we attach a library module to it.....
#x:`global.myLib={}`;
// Then add a method to the module..............
#btoa:`myLib.btoa=function(str){
var buffer = new Buffer((str).toString(), 'binary');
return buffer.toString('base64');
}`;
// And invoke the method to encode some text............................
#sometext:'LESS is more (more or less)';
.test2{
content:`myLib.btoa(#{sometext})`;// content: "TEVTUyBpcyBtb3JlIChtb3JlIG9yIGxlc3Mp";
}
I've recently abandoned mouse-driven, platform-specific GUI editors and committed entirely to vim. The experience so far has been fantastic, but I'm stuck when it comes to Javascript.
The ever-popular taglist utility (using Exuberant Ctags) has been great for everything but Javascript. With the language's overly-free form and structure, taglist could only pick up a handful of functions when I opened it up -- only those defined in the format:
function FUNCNAME (arg1, arg2) {
but no variables or function objects defined like:
var myFunc = function (arg1, arg2) {
So I googled a bit and found the following definition set for ctags, which I put in my ~/.ctags file:
--langdef=js
--langmap=js:.js
--regex-js=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\{/\1/,object/
--regex-js=/([A-Za-z0-9._$()]+)[ \t]*[:=][ \t]*function[ \t]*\(/\1/,function/
--regex-js=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*([^])])/\1/,function/
--regex-js=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\[/\1/,array/
--regex-js=/([^= ]+)[ \t]*=[ \t]*[^""]'[^'']*/\1/,string/
--regex-js=/([^= ]+)[ \t]*=[ \t]*[^'']"[^""]*/\1/,string/
After that, running ctags from the command line was fantastic. It found every function and object that I needed it to find.
The problem is that the taglist.vim plugin isn't seeing those new results. When I open my javascript file in vim and hit :TlistToggle, I get the exact same meager handful of functions I got before. I hit 'u' to update the list, with no effect.
Digging into taglist.vim, I found this:
" java language
let s:tlist_def_java_settings = 'java;p:package;c:class;i:interface;' .
\ 'f:field;m:method'
" javascript language
let s:tlist_def_javascript_settings = 'javascript;f:function'
...which implies we're only looking at one specific kind of output from the ctags utility for javascript. Unfortunately, I'm not savvy enough with taglist or vim in general (yet) to discover what change I can make to get all those wonderful ctags command-line results to show up in vim.
Help appreciated!
Got it! I dove into the taglist.vim code for awhile, and this is what I found:
taglist.vim forces ctags to use the same filetype that vim is using. So even though the ~/.ctags snippet I found via google is assigning my much-needed definitions to the new "js" language and applying it to files that end in .js, taglist is forcing ctags into using the "JavaScript" filetype that vim is using -- which is built right into ctags already.
The solution is to change the ~/.ctags file from what I've posted above to this:
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*new[ \t]+Object\(/\1/o,object/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\{/\1/o,object/
--regex-JavaScript=/([A-Za-z0-9._$()]+)[ \t]*[:=][ \t]*function[ \t]*\(/\1/f,function/
--regex-JavaScript=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*\([^\]\)]*\)/\1/f,function/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*new[ \t]+Array\(/\1/a,array/
--regex-JavaScript=/([A-Za-z0-9._$]+)[ \t]*[:=][ \t]*\[/\1/a,array/
--regex-JavaScript=/([^= ]+)[ \t]*=[ \t]*[^""]'[^'']*/\1/s,string/
--regex-JavaScript=/([^= ]+)[ \t]*=[ \t]*[^'']"[^""]*/\1/s,string/
which alters the pre-existing JavaScript language definition directly, rather than creating a new language definition within ctags. Now, when taglib forces vim's registered filetype, the new definitions are used. Also missing from the previously posted ~/.ctags lines was the "kind" letter that Al mentioned in his answer, so those are included in my updated version as well.
From there, drop the following into your ~/.vimrc to activate the new types:
let g:tlist_javascript_settings = 'javascript;s:string;a:array;o:object;f:function'
All-in-all, the new regex lines aren't perfect -- they'll definitely need some tweaking to avoid a lot of false positives, and it might be nice to separate out constants and such. But now, at least, I have the ability to do that :).
Edit: Added instructions on how to activate types without editing the plugin, and vastly improved the main ctags function regex to avoid some false-positives.
Edit 2: Added more array and object definitions to the ctags regex.
I ran into this post on a google search, and although your findings are excellent, I think we can improve them. This is the results of a bit of hacking on your solution:
.ctags
--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9_$]+) = \[/\1/a,array/
--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9_$]+) = \{/\1/o,object/
--regex-JavaScript=/^var[ \t]+([a-zA-Z0-9_$]+) = (^{^[)+/\1/r,var/
--regex-JavaScript=/^[ \t]*(this\.)?([A-Za-z0-9_$()]+)[ \t]*[:=][ \t]*function[ \t]*\(\)/\2/u,function/
--regex-JavaScript=/^[ \t]*function ([a-z0-9]+[A-Za-z0-9_]*)/\1/u,function/
--regex-JavaScript=/^[ \t]*([A-Za-z0-9]+)\.prototype\.([a-z0-9]+[A-Za-z0-9_]*)/\1 : \2/u,function/
--regex-JavaScript=/^[ \t]*function ([A-Z]+[A-Za-z0-9_]*)/\1/o,object/
.vimrc
let g:tlist_javascript_settings = 'javascript;r:var;s:string;a:array;o:object;u:function'
This gets rid of a few more false positives, and adds some more features in, as a tradeoff for getting rid of some of the more problematic regexes. I'll keep updating if I find I need more.
Edit: I've gotten everything working really nicely now; I feel like this result is solid. The only major deficiency is that it doesn't work on comma separated variable definitions. That seems particularly nasty. Maybe another day. :)
Note also that I changed the .vimrc. This isn't because I'm a freak; it's because somehow taglist or ctags or something has some default values set, and if you don't change it, then you get a lot of doubles where functions and vars are concerned, which really drives me insane (I pay super attention to detail.. :P )
Edit: More tweaks. It picks up on prototype function declarations now, and doesn't do some other stupid stuff.
The best-practice solution, which is also very new, neat and easy way to get JavaScript source-code browsing / tag-list in Vim, is using Mozilla's DoctorJS (formerly known as jsctags).
See my answer for this question for more info.
Enjoy. :)
I've not used javascript or taglist much, but looking through :help taglist-extend, it looks like your definitions (listed above) rename the javascript output to js, so you'll probably need something like (in your vimrc):
let tlist_js_settings = 'js;f:function;m:method'
This is assuming that the ctags 'kind' is 'f' for function and 'm' for method. Have a look at your tags file and see what the 'kind' column looks like. By way of example, my C code tags file includes this line:
ADC_CR1_AWDCH_0 .\LibraryModules\CMSIS\Headers\stm32f10x.h 2871;" d
This is a #define of a symbol ADC_CR1_AWDCH_0, which is in the listed file at line 2871. The 'd' is the ctags 'kind' for a defined name. Hopefully that will give you enough to get you going.
As an aside, I'm not sure whether the override will work correctly, so it might be worth naming your file 'myfile.mjs' and changing your langmap to js:.mjs until it's working properly. Then at least you'll know whether your problems are associated with misidentification of files or the actual parsing.
Hi thanks to Tom Frost for his question and research, I think there is a little problem with the 4th line regexp of your final answer:
--regex-JavaScript=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*\([^\]\)]*\)/\1/f,function/
Doesn't worked for me, I pulled it a bit and now works ok:
--regex-JavaScript=/function[ \t]+([A-Za-z0-9._$]+)[ \t]*\([^\)]*\)/\1/f,function/
PD. The others answers' regexps posted here doesn't work at all at least for me :-?
To avoid duplicate entries from ctags' built in javascript support I define 'js' language as in original post and help taglist use ctags with it. I also make sure that tagnames are stripped from some less useful bits (quotes, "this.", ".prototype"). I don't use object/array/string/var regexps, but it's easy to combine my regexps with the other suggestions.
~/.ctags:
--langdef=js
--langmap=js:.js
--regex-js=/["']?(this\.)?([A-Za-z0-9_$]+)["']?((\.prototype)?(\.[A-Za-z0-9_$]+))?[ \t]*[:=][ \t]*function/\2\5/f,function/
--regex-js=/function[ \t]+([A-Za-z0-9_$]+)/\1/f,function/
~/.vimrc:
let g:tlist_javascript_settings = 'js;f:function'
I know that JavaScript doesn't support macros (Lisp-style ones) but I was wondering if anyone had a solution to maybe simulate macros? I Googled it, and one of the solutions suggested using eval(), but as he said, would be quite costly.
They don't really have to be very fancy. I just want to do simple stuff with them. And it shouldn't make debugging significantly harder :)
You could use parenscript. That'll give you macros for Javascript.
A library by Mozilla (called SweetJS) is designed to simulate macros in JavaScript. For example, you can use SweetJS to replace the function keyword with def.
One can also now use ClojureScript to compile clojure to javascript and get macros that way. Note ClojureScript uses Google Closure.
I've written a gameboy emulator in javascript and I simulate macros for cpu emulation this way:
macro code (the function returns a string with the macro code):
function CPU_CP_A(R,C) { // this function simulates the CP instruction,
return ''+ // sets CPU flags and stores in CCC the number
'FZ=(RA=='+R+');'+ // of cpu cycles needed
'FN=1;'+
'FC=RA<'+R+';'+
'FH=(RA&0x0F)<('+R+'&0x0F);'+
'ICC='+C+';';
}
Using the "macro", so the code is generated "on the fly" and we don't need to make function calls to it or write lots of repeated code for each istruction...
OP[0xB8]=new Function(CPU_CP_A('RB',4)); // CP B
OP[0xB9]=new Function(CPU_CP_A('RC',4)); // CP C
OP[0xBA]=new Function(CPU_CP_A('RD',4)); // CP D
OP[0xBB]=new Function(CPU_CP_A('RE',4)); // CP E
OP[0xBC]=new Function('T1=HL>>8;'+CPU_CP_A('T1',4)); // CP H
OP[0xBD]=new Function('T1=HL&0xFF;'+CPU_CP_A('T1',4)); // CP L
OP[0xBE]=new Function('T1=MEM[HL];'+CPU_CP_A('T1',8)); // CP (HL)
OP[0xBF]=new Function(CPU_CP_A('RA',4)); // CP A
Now we can execute emulated code like this:
OP[MEM[PC]](); // MEM is an array of bytes and PC the program counter
Hope it helps...
function unless(condition,body) {
return 'if(! '+condition.toSource()+'() ) {' + body.toSource()+'(); }';
}
eval(unless( function() {
return false;
}, function() {
alert("OK");
}));
LispyScript is the latest language that compiles to Javascript, that supports macros. It has a Lisp like tree syntax, but also maintains the same Javascript semantics.
Disclaimer: I am the author of LispyScript.
Check out the Linux/Unix/GNU M4 processor. It is a generic and powerful macro processor for any language. It is especially oriented towards Algol-style languages of which JavaScript is a member.
Javascript is interpreted. Eval isn't any more costly that anything else in Javascript.