Skip to content
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

Stylus AST guidelines #2052

Open
buzinas opened this issue Nov 23, 2015 · 6 comments
Open

Stylus AST guidelines #2052

buzinas opened this issue Nov 23, 2015 · 6 comments

Comments

@buzinas
Copy link

buzinas commented Nov 23, 2015

I'm developing a VS Code extension that will provide Stylus Language support (already did some work, but I want to be able to offer full intellisense support, and I'm getting kindda stuck with the Stylus AST).

Is there any guidelines I can find? Tried lots of google combinations, and looked some issues here, a question on SO, but didn't find any documentation that could help me for what I need.

One example:

body
  width w = 1024px
  height w

When I'm defining global scoped variables, I can use evaluator.lookup(variableName) to find it, and then, use, for example, Go to Definition, etc. How can I find the local variable w in this example?

Is there anyone available to help me with some specific trouble I'm having, so I can get faster into the Stylus AST, and be able to create a great extension for VS Code? Maybe I can even port it to other editors - all of the Stylus plugins/extensions I found were only coloring/snippets, not one single real language support.

Thanks in advance!

@Panya
Copy link
Member

Panya commented Nov 23, 2015

Hi!

Unfortunately we don't have any documentation for AST and other internal parts of Stylus currently. But you can post your questions here or on SO, I'll be glad to help.

One example:

body
 width w = 1024px
 height w

On the particular question you can use evaluator.currentScope.lookup('w') to get the variable.

@buzinas
Copy link
Author

buzinas commented Nov 23, 2015

@Panya thanks for the fast response.

I'd already tried that before, but in fact, my current scope is always the root, since what I'm doing, basically, is:

/* this is VS Code stuff, basically, I'm creating some hover experience
   when someone hover a word, if it's a defined variable/function, I want to show the body, e.g:

       x = 1024px;
       body
         width x

   if we hover the second x, I'm showing `x = 1024px` in a hover
   for a function, e.g:

        border-radius()
          -webkit-border-radius arguments
          border-radius arguments

       .card
         border-radius 2px

    if we hover the second borde-radius, I show exactly the declaration and its body
    btw, I'm already doing that, and it's working, but I only handle the global scope atm */

const hoveredWord = document.getText(document.getWordRangeAtPosition(position));
const parser = new Stylus.Parser(document.getText());
const ast: Stylus.Nodes.Root = parser.parse();

const evaluator: Stylus.Evaluator = new Stylus.Evaluator(ast);
evaluator.evaluate();

const hoverText = this.getHoverText(hoveredWord, evaluator);

My main questions atm are:

  • Is there any way I can list all the scopes?
  • Given a current position (line, column etc), how can I get the last child node accordingly?
  • Given a node, is there a way to get its scope?

Thanks again for the fast response! :)

@Panya
Copy link
Member

Panya commented Nov 23, 2015

Is there any way I can list all the scopes?

Yep, you can iterate through evaluator.stack to get all frames with their scopes, like so:

var stack = evaluator.stack;
// length - 1 — current frame, 0 — global
for (var i = stack.length - 1; i >= 0; i--) {
  console.log(stack[i].scope);
}

Given a current position (line, column etc), how can I get the last child node accordingly?

Unfortunately , there is no such method. You can try to iterate through children of the AST to find closest node by its lineno and column properties.

Given a node, is there a way to get its scope?

Well, this is complicated too. Only Block nodes may have scope, and children of the block (except other blocks) don't have a link to its parent. So, anyway you should try to find closest block to the node to get its scope (you can use evaluator.stack.getBlockFrame(block).scope in this case).

@buzinas
Copy link
Author

buzinas commented Nov 23, 2015

@Panya thanks again!

Probably I'll be able to do more stuff for now!

One last question: is there any method that iterate through the children?
I was trying to do one, but there are so many different kind of nodes, that I thought maybe you already have that internally, and I don't need to reinvent the wheel.

Thanks in advance, and I'll get back with more questions, when I get stuck again!

@Panya
Copy link
Member

Panya commented Nov 23, 2015

One last question: is there any method that iterate through the children?
I was trying to do one, but there are so many different kind of nodes, that I thought maybe you already have that internally, and I don't need to reinvent the wheel.

We inherit the Visitor object (visitor/index.js) and define methods for different nodes (like in visitor/evaluator.js (visitIdent, visitImport, visitMedia etc.)). A list of all possible nodes is defined here.

@SimenB
Copy link
Contributor

SimenB commented Oct 9, 2016

@Panya Would it be possible to extract the parser/AST into a separate project?

I'm working on stylint (a linter, https://github.com/SimenB/stylint), and while the current regex based solution works fine, it'd be great to be able to use actual AST for it. And I'd like to avoid having a dep on stylus itself, to allow the consumer to use the version they want themselves.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants