[Music]
okay good day my name is Tony I work at
the nomic foundation in applied
research uh I was previously a co-lead
on the slang project and it's in this
capacity that I'm going to speak to you
today
I have a fantastic job working with
excellent people at nomc nomic is a
nonprofit and our number one core value
is kindness and we live this every day
and we are hiring there's meant to be a
QR code at the end of my slides but I'm
afraid it didn't make it uh and I want
to give heartfelt thanks to the
co-founders of nomic p and Fran for
creating and maintaining such an amazing
place to
work so today we're going to explore the
slang query API which is a new feature
which makes working with solidity code
surprisingly straightforward and now
this is not a tutorial so some of the
details have been omitted you can't copy
and paste any of the code that I'm going
to be providing it's just so that you
can well I'm hoping to inspire you so
that you uh go and find out some more
details okay so 20 minutes
is a bit of a Sprint so I'm going to
speed up let's
go okay so what is slang so slang's our
solidity compiler Library it's uh
basically a developer tool that enables
you to write better tools it passes and
analyzes solidity code from version
0.4.1 to the latest
0.8 which is basically all of the cility
code that is
live uh our focus is on correctness and
convenience uh we're about to release
version one which covers the typical
front end features of a compiler and our
main objective as I said is to enable
you to develop better
tools uh slang has a radical open uh
declarative met
architecture slang's a error correcting
compiler so it always produces output
even if you've got source code errors
uh a key feature of slang which is what
we're here to talk about is its query
API for code
analysis so compiler front ends fall
into two main categories there are those
that produce what's called concrete
syntax trees and then produce an
abstract syntax tree from that and there
are those that produce abstract syntax
trees
directly uh so what's the difference
between concrete syntax and Abstract
syntax well concrete syntax as you can
see on this slide is a complete
representation of the source code it
includes every character every bit of
Whit space every comment it's like
having as I say like having the full
book like a
PDF uh whereas an abstract syntax
tree is a simplified tree representation
so it doesn't include wh space and equal
signs and and punctuation it's just got
the essential
details like if you were reading the the
plot of a book but you didn't actually
have the
text so here's an example of a contract
of a concrete syntax tree so we've got a
simple variable declaration here and
every single element of the original
source is represented nothing is removed
or
simplified now this is different from an
as which will eliminate some of these
details so if we look what we've got
here it's a simple variable declaration
now it consists of a type name which
which is uint then some wh space an
identifier some wh space punctuation
your equal sign some Whit space a number
literal one and then the
semicolon now what's crucial to
understand is that we're preserving
every single character in fact even if
there's an error in the source code
you'll find it in the concrete syntax
tree so why is this important well when
we're developing uh building developer
tools uh or transforming code we often
need the complete information so we can
round trip if we were just concerned
with the meaning of the code then we'd
use an abstract syntax tree but for many
tools like formatters linters or
refactoring tools we often want the full
syntactic details you don't want to lose
comments when you're
refactoring uh and sometimes you want to
know if you've left two blank lines uh
and you want to preserve
that this level of detail is great but
it's also challenging it's quite
difficult to process this on the one
hand we have complete information but
working with detailed trees can be
complex and that's the challenge that
the query API solves so from now on I'll
admit trivia nodes and white space from
the examples they're still there but you
I don't need to show them so let's look
at a slightly more complex example this
definition shows how different elements
Nest within each
other uh and once again notice how
everything is preserved here we've got a
function definition we've got the the
keyword function the identifier we've
got a parameter list which in this case
is empty but we still preserve it and
then nested in that is a block and a
return statement and so
on now this level of detail allows us to
maintain complete Source Fidelity as I
said if we're going to roundtrip we can
track precise cord code locations so if
you want to do error
reporting uh it handles formatting
preservation and when you're Building
Development tools this detailed
structure is
essential for certain class of
development
tools so to emphasize this point and I
know I'm being repetitive here I really
want to make this point though why do we
need a concrete syntax tree well we
really want to in a lot of tools for
example in pra uh which is now used
using slang by the way using this
technology uh pretty a solidity we want
to make sure that we can preserve every
single character especially comments for
example you might have a tool that wants
to deal with comments wants to encode
validation information in a special
comment format not like the
documentation comment but your own
special comment format so you want to
preserve those
comments an as on the other hand is
focusing on the essential structure
which is good for seman processing
doesn't contain the formatting
information simplifies
expressions and it adits all comments in
white
space so now that we understand what a
CST is for let's look at how you might
traditionally process a CST so this is
the kind of code that you often see a
lot of you know what it's like to
Traverse a tree especially a very deep
and complex tree which which is what you
typically get out of a
compiler uh and it's not pretty what
we're trying to do is actually quite
simple we just want to find all the
variable declarations in some solidity
code but look at what we have to
do so first of all we're writing a
recursive function we need recursion
because we don't know how deep in the
tree it is could be at the contract
inside a function inside a block
anywhere and then when we find each node
we've got to manually check its kind
we've got to search through the uh
children we've got to handle all the
edge cases and we've got to manage the
recursion stack especially if you're
threading State and this is a simple
example in real life code you'd have to
handle Eric cases deal with unexpected
node types which is what you can get if
you've got a source code error for
example manage your state during
traversal and if you've written a
visitor patent you know that it's a pain
in the ask to manage your
state you've got to handle parent
refence es and you've got to manage the
position in the source
code now the problems with this approach
are numerous first it's incredibly
verbose the amount of code you need to
write to do even simple analysis is
substantial and the more code you write
the more you have to maintain and the
more places there are for bugs to
hide uh second it's Error prone uh not
only because of the volume of the code
but also it's quite tricky to write
these when you're dealing with
complicated trees for example in
solidity variable declarations can
appear in for loop initializers I don't
know if this code would handle
that it's a question for the reader it's
hard to maintain when the language
evolves and as you know solidity evolves
significantly uh in all sorts of
interesting ways like in one of the 0.5s
where the exponentiation operator
changed
associativity uh so when the language
evolves you need to update your
traversal code and that's because the
veral code is mixed with the analysis
code so what you want to do for analysis
is mixed in with the mechanics of
traversal to make changes you're often
going to break things finally and more
importantly this forces you to think
about what or how you want to do things
rather than what you want to do and the
intent of this code finding variable
declarations is buried in here you could
look at a big tra bit of traversal code
and you wouldn't know what it was meant
to be doing
we need something
better so we'll have a look at some
specific challenges with manual
traversal so recursion management you've
got to handle deep nesting efficiently
avoiding stack Overflow you've got to
make sure you don't have any infinite
Loops you've got to maintain your
context State Management you got to know
when to stop recursing once again if you
use a visitor pattern where you've got
an external visitor driving external
code driving your visitor you often want
to stop top or you don't want to go into
the children of this node how do you do
that that means you end up with a more
complicated API State tracking is quite
complex you need to keep track of the
parent node when you're um uh walking a
tree you need to maintain scope
information in the case of a compiler
build up your composite results handle
cross node relationships I.E you want to
link this node which you visited you
know 30 minutes ago with this other node
which you're visiting
now now error handling multiplies the
complexity and edge cases keep appearing
for example parenthesized Expressions
nested structures optional elements and
language specific quirks of which there
are plenty in
solidity and finally you've got a big
maintenance budget now I know I'm
repeating this point but this is
significant as you'll see when we get to
queries which I think is the next
slide so this is where queries come in
so let's look at how we solve some of
those same problems using queries so
this is our first example we want to
find all the unit variable uh all the
uint variable
declarations it's as simple as saying
inv variable declarations where the type
name is uint and it's got an identifier
bind that and return it no
traversal no edge cases hardly any
maintenance no efficiency problems so
the second example shows something a bit
more powerful in this case we want to
find immediately nested function
declarations are a function inside
another
function so here we're saying in every
contract definition there are some
contract members in the contract members
is a contract member for every function
definition in there find the block and
look for the a statement in there that
is a itself a function definition call
bind that to a variable called tested
and return
it so why is this so powerful well first
of all it's declarative we it's saying
what we want not how we want to do it
makes that code easier to understand and
maintain and when you look at this two
months later it's obvious what it's
doing whereas I'd suggest that you'd
have a couple of pages of code
traversing your tree if you were using
manual traversal and it wouldn't be
obvious what it was actually meant to
do so it's structure aware
so the query understands solidity syntax
structure it knows about scope and it
knows about nesting and it also knows
where type name for example in the in
the first case here appears in the
tree these patterns are composable so we
can build complex pattern matching from
simple pattern matching so if we wanted
to find uint variables Within These
nested function definitions it would be
as simple as put putting that appending
that first query below the second query
but most
importantly this is focusing once again
on what we're trying to achieve we can
think about code patterns and structure
design without getting bobbed bogged
down in the implementation
details so let's have a look at some
more advanced query
patterns this one for well this one
isn't that advanced but for example in
an unchecked block you want to find all
function calls as easy of that and it's
obvious what it does you could write
this on one
line the second example is a bit more
complicated but here we're looking for
variable
declarations uh State variable
declarations that have a type that is
either map a mapping or an
array and think about what this would
take if you doing manual traversal You'
need scope tracking type checking logic
complex conditional logic and you'd need
to hand carefully handle the nested
structure
here so what are the use cases for this
or some use cases CU I'm hoping that
people come up with far more use cases
than we know we want sort of emergent
benefits from this well if you wanted to
have custom coding standards you want to
enforce custom coding standards you've
got project specific restrictions that
you want to check or you want to do
version compatibility check so you want
to make sure that you don't use certain
featur pies of
solidity uh style checking well if
you've got specific naming patterns you
want to enforce uh specific structural
conventions and you can have context
Weare rules now you might be thinking
well can't I use a linter to do this
well yes but this is meant to write the
linter this is designed for writing
linters so that's why these are the use
cases this is not an end user tool this
is a tool for developers to write tools
uh so you can do patent detection anti
patents for example uh optimization
opportunities which may not be
immediately obvious if you've got a big
library of things uh detecting complex
structural patterns that you might want
to simplify or or Mark so once again
this is a kind of an es linter uh
equivalent code transformation automated
refactoring refactoring is
Transformations that um preserve the
semantics uh code modernization it's
very easy to write
um patterns that then transform into uh
more modern code automated modifications
i. things that aren't refactorings that
actually change the code and formatting
and as I said uh pretty solidity is
already using uh
slang uh one important point I want to
make here is that uh we support WM and
we support in spe specifically the
component spec and WID so for those who
know what that means this means that uh
all of this technology works in the
browser it's also available as a rust
API or uh as typescript which is our
first Target because most people uh are
using
typescript so some more applications
code trans I've already done that
documentation generation uh it's easy to
generate automatic documents by
extracting function signatures doing
structure analysis um checking for
particular usage patterns and
documenting them and processing comments
as I mentioned before you might have
validation uh information in a certain
specialized Contex uh comment format now
you can also use this technology in
combination with AI tooling for example
to produce uh diagrams from your code
you can use this with uh by encoding uh
the slang API as a
rag so what are the key benefits well
structure aware queries your queries
naturally align with a structure of the
code that you're trying to match you
don't have to think about trees and
nodes and and uh
traversal uh complete syntax
preservation you never lose
information perform Transformations
without losing the formatting and you
can round trip from a
CST uh back to
Source efficient patent matching so we
can spend all the effort required to
make this efficient if you know anything
about the state-of-the-art in terms of
tree pattern matching and in fact we're
not a a search engine we are a unifier
so we use a prolog datalog based uh
mechanism which returns you all the
potential matching results not just the
first one you can avoid unnecessary
traversals we can case results we can
index the syntax tree make it very
efficient it would take a lot of effort
to uh get the same uh result if you
doing it yourself
composable syntax rules you can combine
simple rules to make bigger ones you can
have a big library of these uh pattern
and you can reuse them uh over your code
share queries between your
projects you've got maintainable
analysis code so the queries express
your intent not how you not what you
want to do uh how you want to do it but
what you want to do your code is shorter
it's easier to understand any changes to
the language we say ter that slang takes
care of that so you don't have to less
code means fewer bugs and these benefits
compound it's not 1+ 1+ one it's you
know far this the uh whole is far
greater than the sum of the
parts so what impact does this have on
your development well before using this
query API it spend significant time
writing and debugging the traversal code
you'd struggle with maintaining the
analysis logic and you'd face challenges
when adding new
features after it you end up with clear
Focus code it's easy to maintain you've
got a robust implementation and it's
highly
extensible and that is it any
questions fantastic thank you Anthony
all right let's get with the let's get
with the questions so folks remember you
can scan that QR code add questions to
that list smash that up vote button that
the most interesting question gets asked
let's go with the first one what are
advantages to using slang compared to
srep uh well I must admit I'm not
familiar with uh srep but I know the
general uh concept the specific thing
here that this is a programmatic tool
that you use to build other tools now of
course you can combine things like
srep uh I imagine uh but I don't know if
that is something that you would include
in a tool for analyzing lots of
different versions of solidity that
makes sense thank you how does slang
differ from a fine-tuned llm could
slang's modularity allow to use llms in
the future oh this is I'm in applied
research and uh this is something that
is very actively under research I'm not
making any commitment uh but if you've
used fine-tuned llms uh and I've used
them a lot for example a lot of the code
that I write is actually written by
Claude uh a lot of this presentation was
written by Claude um amazing tool but
you always need a human in the loop so
yes you can do this uh using llms but
the thing with llms is that they are a
human augmentation tool whereas the
approach that we're talking about here
is exact and precise if you've used llms
to do this you know that you you spend a
lot of time on prompt engineering and
then you cross your fingers and
something comes back and it doesn't
quite work and you prompt it again and
so on and so forth so yes this is
certainly something that uh could be
included in the future there's a chance
but maybe not now I mean not immediately
certainly not now okay are the
limitations of an of a tree visitor
based approach not solved by using an
API with CFG and intermediate
representation like Slither
provides
uh well if if by CFG well you're either
meaning two things you're either meaning
the control flow graph uh which is
typically something you'd find in an
abstract syntax tree uh or if you mean
control flow as exposed by rust for
example uh and this is something where
you reify your control flow so you
return a token in your visitor which
says do you want to continue do you want
to go down uh the trees um now this Tree
Visitor uh these
um solution
these Slither May well um solve the same
kind of problem we have a different set
of constraints for example our query
language uh is intended to be extended
with semantic predicates and with the
ability to do arbitrary recursion by
skipping over arbitrary subtes uh so
there's a lot that we want to do there
so I wouldn't say that that um in
slyther you can or cannot do that I'm
not familiar enough with slither perfect
thank you is there a question you like
most in
there uh well will this work with
different evm versions yes it will
because we're dealing with Source where
well before evm slang is a compiler and
it'll produce bite code so that's a
question about the compiler not about
querying have we published the grammar
for slang yes we have uh slang is
actually a uh declarative meta project
so you can use it for any programming
language not just solidity and we have
um published that everything we do is
open source uh
nomic foundation on GitHub all of our
development is in the open you can reuse
all of this
awesome uh how important well uh so how
important is it to maintain code with
different solidity versions why why not
just use one version because if you want
to be able to provide tools that analyze
a large number of contracts which may be
an earlier version of solidity than the
latest one for example
0411 there's a a contract on mainnet
that is 0411 you want to get the source
to that you want to um provide analysis
tools for it that's why we want to
support all of these versions now we
don't go back to 001 or whatever the
first version was so we're pragmatic
about it but these are the versions that
are live and our goal is to support all
the versions that are live how do you
determine the cut off
version uh what's analysis an analysis
of the of m net and all the contracts
that are live okay is it the number of
contract is it the value stored in those
is it the amount of transactions no the
earliest the um I didn't do this
analysis so I must admit I don't know
what process we use to determine that
but it is the case that the earliest
contract in use apparently is 0411
fantastic thank you um what's the best
practice for using slang to analyze a
large number of program where should the
data be stored and in what format
imagine this is something you run
locally correct yes it is perfect thank
you all right what update in solidity
was the artist to that for you mentioned
quirks and weird updates in solidity
which one was the hardest
or none of them was particularly hard uh
the volume of quirks is what is a
challenge I mean we've we've got
hundreds of edge cases we had to analyze
Sal C because that's the only definition
of the language uh and go through the
code and then test it and then go to
sanctuary and look at massive uh numbers
of
contracts uh run uh our compiler over
them or run our paer over them what
breaks what doesn't we've got extensive
uh test cases so that was the challenge
it's the number not not any particular
difficulty fantastic thank you do you
dream in bite code uh no no I don't
dream I dream compilers actually all
right Anthony thank you a lot for your
time and all the best to you thank you
people our next session will start in a
few minutes I am off for today thank you
for those who spent a bit of time with
me this morning um and I'll see you soon