Parsing (more) CSS component values with the proc-macro

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
yesterday we have written a nice little procedural macro that we can use to generate pass impulse for the CSS property values and you can see an example of that right here we have either a color value or a transparent or inherent keyword for a background color value that's pretty simple and it works very fine um but I need to extend it a little so what I want to do today is first I want to rewrite the macro so we don't work with these strings anymore and instead I want to use the quote Library which allows us to um yes they have the example right here which allows us to use rust code and get syntax highlighting but under the hood it more or less does a similar thing so I want to use that and I don't expect that to take too long I think we can do that pretty quickly and after that I want to be able to support more of the component value combinators which is sort of a regex-like syntax used for CSS parsing I want to support more of that inside of the macro so we can pass more property values for example the CSS display property which and you can see right here and as you can see it is rather complex it has many different options um but I will get to that into in more detail once we finish using the quote Library okay so first thing we should do is actually import quote I guess that's uh chord version one we checked that yesterday and we also need proc macro 2. because I saw on the create page or a documentation page that they use prop macro tool because the craftmaker 2 is basically just a re-explored version of the compiler internal proc macro Library so that it can be used and creates outside of procedural macros and in unit tests Etc and I believe that's also version one okay and then we can kind of rewrite this such that um we don't use strings here anymore instead we use Road macro and we basically write the same thing um like this don't need the double brackets anymore and then um here I want to insert the value type DOT type type name and no that's the that's the variant I'm messing it up this one should be the value type type name and this one should be the battery um so I guess I need to import well the image is not loading that's weird um so I guess I need to import the quote macro probably what are you complaining about cannot find macro quote here so I need to use code but bomb and then what are you complaining about now the quote value type to tokens is not satisfied so I suppose I need the actual identifier probably uh value type dot variant type uh um yeah maybe let's let's scratch these structs maybe because I'm not sure if we can use this uh this direct field access syntax Within um the quote macro maybe just change it to um type name variant and then we are inside the value type code so I do want um I do quality value type name and the background but items right because I believe we do need the identifiers uh-huh and did I in already I did explicitly is the vector type in here that's not good don't need to do that um okay so now I want just the type name and just the variant and it still doesn't work um expected empty type found token stream I suppose I do need to delete the part down here yeah and now it works and now it's complaining because of course we're no longer using strings we are using token strips and I want to collect these into a vector although I want to join them immediately um can I just concatenate them and I suppose I should um also import tokens um I guess I could import it as tokenstream 2. 2 token 3 as token stream 2. I guess that's reasonable so I want to collect it as a token stream and now I wonder whether it will just concatenate it all for me I guess it's not complaining anymore then let's do the same thing for the for the keyword code first of all let's get rid of the keyword type don't need you anymore you can go as well and then in the future I just want you to um be the keyword and variant items right I think that's right um no I'd you shouldn't be a literal string or actually you can be a literal string that's fine it's a keyboard after all it's a string it rule it makes sense okay then now I want you to be the quote macro and you don't need this string thing anymore and don't need you anymore and you can just be the keyword and we want to map you to the variants and of course I need to add them in here as well keyword variant don't need these arguments anymore and that should be it right and we want to collect you into a token stream as well um but actually I need to add the comma Now hopefully that just works as expected if not I'll be disappointed um okay can I just take a reference will that cause lifetime issues cannot move out of variant dot Island which is behind a shared reference I do not want to do that it's actually fine with a reference okay cool very cool um okay so now I want to use the quote macro in here as well and let's go ahead and do that don't meet you anymore don't need you anymore all of this can become single braces curly braces a nice thing is that now we actually get syntax highlighting and it just becomes way easier to debug that I remove might have removed one price too much you should belong to this one up here so why don't you do that because there's one still left in here okay and then we can no longer get an invalid rust called error because we're using the macro which will always produce a villa Temple so let's um I guess we can just do this and then don't call that into on it move this down here will that just work that would be very nice and we are not using the keyboard match at all that is not great um let's include them in here and let's add the value type code here value type code again variable names are not that great right now but I also don't really care and we don't use the enumn name anymore that is also not correct we want to use the enumn name please give me the email name okay and that seems like it could work but we're getting an error expected pattern found comma all right because I have um still have the extra comma in here after the keyword match because all of them now have their own commas um no method name type name found for enum Constructor I don't want to to call type name function that seems like I forgot to escape something yeah I did I did I did um just variant that should work maybe I believe in the dream not seeing any errors does it still pass fine it takes a while to compile but it looks like parsing is still as usual okay great so I think it's this is a no-brainer really it's very obvious to me or rather I think it's very obvious that this is a good change and that we should keep it that way um yeah rust format still wants to complain a little um I wonder if I should change anything else um I think the panics are all fine yeah I think I think those are fine so let's commit this um get at web CSS property derived and I want to add everything I believe yep also at cargo.log but I still have some other changes yeah yeah okay um good then let's come with that git commit and CSS property derived use quote instead of strings um problem is that the create name is so long that there's not that much space left for the actual commit message um this allows us to get stuff like sometimes highlighting and auto completion match ES editing experience because the code as we had it previously was kind of a mess to be honest was not really Pleasant to write or read very cool um by the way regarding my use of dependencies I generally try to use as little dependencies as possible within the browser um at least at runtime but for procedural macros rust proc macros basically you have to use these three crates that I've imported here if you want to write any kind of serious proc macro it just doesn't work without them and um I don't really count them as dependencies because the way rust dependencies work is that the rust foundation will kind of push responsibility for certain features onto the community to develop these kind of crates as they've kind of done with and of course these three but also async runtimes are a good example of that and then once these crates in the community are performing well and they are kind of a clear winner has emerged then they'll try to integrate them back into the standard Library so I am fine with these three dependencies and of course they also just use that compile time which I believe is fair I mean you can certainly try writing a macro broad macro without some um Good Luck that should I should add space here do I not format cargo terminal files let's add this as well and then edit on to the second task for today which is um supporting component value combinators so we can pass the CSS display value so as you can see there's a clear list of combinators that we can use and right now the only one that we support is the bar operator so in the code that looks like this um we have either a color or a transparent keyword or a inherit keyword but um nothing else and that is exactly what the power operator does separates two or more Alternatives exactly one of them must occur but I also want to support these three operators and then brackets the um the last one we can just support that we are types that's not a problem but I want to add support for these three so first of all we have um just the space as a combinator which means that the component is followed by another component and both of them must occur and then there's the Ampersand which means that we have two or more components all of them must occur but the order is not relevant and last but not least the double bar means that there's two or more options and at least one of them must occur but others can be left out and the order is not relevant and the way I want to do this um is by adding something like uh popping on display value and for example the display value can be a display outside or display inside but the order does not matter and you can also leave out either link display outside all the display inside so what I want to do is um add a variant that is extract I'm not quite sure what to call it right now it doesn't matter for now and this is just a placeholder name first is apparently a keyword okay let's call it Foo um doesn't matter for now capitalizing of course um and then the struct will have two Fields namely outside display outside and inside display inside and those should both be optional because um you can leave one of them out technically this would allow for the um would allow both to be left out um at the type level at least of course the parser won't tolerate that but um the type itself would allow for that state which is not really great um but I think that's something that we just have to live with for now because the only other option would be to create a sort of sub enum which creates all the possible combinations and that's going to grow exponentially so I think it's fine to just store these as options for now and then I would annotate this struct field with something like in this case it's unordered right and I guess why we added we can also add a spec link I try to add spec links everywhere where it's possible derive this stuff and then um I guess we can sketch out display outside in display instead as well I think those are very simple um display outside right this just uh four different books um keywords I mean copy debug partial equal right amount ah because you know before partially equal equal and of course CSS property and then we want to create a enum of display outside and display outside can be either a block an inline or a run-in -line run in okay and then this is a keyword which is block and this one is a keyboard that's in line and this one is a keyword that is running and it passes that is very nice I like this macro a lot and I believe the display inside is just as simple so we're going to sketch those two out two display inside here right it's that just has a bit a few more variants you need to update this backlink as well okay it can be either a flow a flow root a table or a one of the other ones I don't really understand what ruby elements are I haven't seen them anywhere before on the web there probably is one of these really exotic features that no one actually uses um but I guess at some point we'll have to implement them as well we'll do it when we get there no food be all of these need to become keywords it's kind of cumbersome but there's no way around it I mean writing an actual parser would be way way way more cumbersome flow and we have a flow root with a dash in between then we have a table a clicks a grid and a ruby element very nice okay so um that's those properties just for example and then um if the display value could for example have another field like bar and it's just for and just for demonstration purposes let's add the same but let's say that we care about the order then we could add an annotation here or not right and what was the last combinator that we need to support [Music] um um we have this one we have this one so um I guess for the last one we would we would have optional unordered so I believe this one would actually be optional and other than not just an order so we need to basically add three more keywords and we need to add support for um struct fields proc macro derived panic yeah um I guess that's to be expected that our macro panics funnel okay um then let's go into the code and then down here I guess we want to check if it's an a struct variant check if it's a extract variant like four bus okay and how do we do that um one other thing that I'll at some point need to think about is that the outermost container that one can of course also be a struct right um because right now we kind of assume that we have a list of variants that could have occur but it could also be the case that um the outermost thing is just an optional unordered obstruct um but I think that is very rare because almost all properties support the inherent or initial keyword and that makes them an enum so it is definitely something that we can worry about later okay um then I guess let's go back to the student documentation and find out how we can pass struck I never know how to pronounce and by the way foreign tributes right where we are inside the variants and now we want to find out if a variant is a struct um and I guess that's the case if the fields are named right yeah we have Fields named um can we maybe uh I think we can clean this code up a little because if it's a named field then we have a struct variant um if it's an unknown field we have an inner variant and if it's a unit type then we have a keyword but um right now this code allows us to specify a keyword for an income variant which is not really great so let's maybe refactor this a little match variants and if it's a zoom fields named name to this then we just escape to do because we don't support struct field sets if it's a if it's a unnamed field s then we basically want to paste the code that we have down there um right yeah we basically just want to use this code and if it's a soon unit then we can go and check if it's a keyboard variant [Music] take this code and paste it over here and then we also don't need this Panic anymore because we can panic in the individual branches if something goes wrong I wonder if there's some nice way to prevent these very deep nesting levels with sin I haven't found one yet I guess that's just something that we'll have to live with for now by the way do you still Panic if I no if I comment out the new syntax then it works fine okay nice so I didn't break anything with these changes okay um so if there's not a keyword attribute then we probably also want to panic Panic um units track unit variants must have a keyword that's fair and then if I test that out quickly if I comment out the new syntax that breaks everything and I also comment out this block then this should panic because it does not have a keyword attribute nice it's my rust analyzer analyzer dying again yep it is wait is it um something's panicking don't know what I don't know if it's my code that could actually be my code all right right the Panic message is CSS property variant must either have an Associated possible value or a keyword annotation so that is just the proc macro process that's dying okay um then now we want to if we have these name fields then we want to find out whether there are um whether there are any um annotations on it and we have three three annotations that we support namely maybe make comment for this find out if one 100 page exists on the field we want to have either an ordered fields hold this required in exact order or we want to have a unordered which is all Fields required but Auto does not matter I believe yeah all of which must have occurred in any order um can I I can even link to the combinator very nice um no that's that's the wrong one but maybe some quotes around that just jacked up a position this one doesn't have a link fair enough uh this is just this backlink I want the this thing the link to the combinator all feels required any of um and the last one is if it's unordered and optional and how do I what a nice way I want I don't really want to use an optional unordered because that's kind of two things um I could use two separate keywords maybe like optional and hmm [Music] I'm not sure about this um I guess optional could be fine no optional it's not fine um I guess optional I don't really like it um at least one any other okay um so we basically want to do the same thing that we have going on down here maybe we can simplify this a little foreign what what does the syntax tree look like if there's ah then it's not a name value and instead it is a path and and I want to check if the if the path is um well actually this thing and why is this even optional all right because it can be there can be multiple components to a path and the island um returns none if there's more than one component um how do I do this nicely um first thing that I want to find out is which one of the three variants it is but then later um I mean the code gen in general comes becomes comes later right uh struct types variable names and soon always are confusing to me and then a struct type is a let's create an enum for this in um struct field constraints or maybe field constraints and this can be ordered or unordered or optional and we want to derive the user usual stuff for it even though we don't probably don't really need it equal that's kind of the um use usual stuff that I derive for enums okay and then um I want to do let's um constraints equal match path string forecast draf and then if you are some audit foreign orders if you are some on order and I want to return field cons constraints unordered and if you are some optional optional then I won't return field constraints optional unordered and otherwise I just want to continue just look at the next attribute because this one is um yeah because this one is obviously not meant for us we don't understand it so ignore it okay and then I want to um probably get all the struct fields and their names into a vector so I can pass that one later all right um how do I want to do this um I mean what do I need to store I need to store let's just write it out correct type stop push and what I want to push I want to push the constraint that I just passed and then I want to also push a vector of um the struct fields and their names and specifically they're the structure types and their names right do I need the uh yes I do need that yes um right um something that I can do is um actually add a impulse for a pass employer for optional types let me quickly go ahead and do that um let's go into this syntax departure and then down here CSS parse everything that or an option that implies CSS parse um should also be able to be parsed because we just want to pass the optional type in that case for option t ARs and that is then a optional value and then I would just want to call tposs does that work it does not but that's the error there it is um expected result right because this can never fail we also always want to return okay I think we're going to need this later okay um so I want to collect all the struct fields and the types right um collect all the field names and their types actually can I maybe just store the named fields um what do the name fields look like so it feels uh Field's name was not feels unnamed I won't feel snapped yeah so it's literally just pretty much a vector of fields I can work with that and the fields have I don't which is not in our case is never known and a and a type nice um and we can probably keep the type as is I believe yeah we can probably keep the time so let's just store the fields name to there don't need another reference in there cannot find Value constrained because this constraints don't need to click this and then down here where's the another dead again still dying because of my macro changes um wait why why are you unhappy about this oh right because um for debugging reasons it's also very painful to debug anything if the T doesn't imply debug and debug it I think is a reasonable constraint so CSS path requires debug [Music] okay so now later in the code gen I want to iterate over the code again so add it down here let's struct variants code equal what did I call it the variable names are just terrible um I mean they are also abstract so I don't really know what else to call them if you have any idea on what I should call them then maybe let me know I'm open for any suggestions at this point um okay so we have a constraint and a named pits and we want to collect that in two a tokens three two okay and um basically match on the constraints of course and if it let's start with the simplest case if it's ordered and then if it's anything else let's just Panic for now so if we have an ordered um thing then we want to pass each field as is basically so um [Music] Let's uh equal uh how do I want to do this this is really not easy oh I guess I also need the variant name right yes I I do of course leave the variant name and then in here I need to add this okay so I um rust format don't be annoying please just going to get large and it trust me I need the braces um Jesus Christ I have formed on safe on this is really annoying um okay let's let's just start writing code and maybe it will get it will at some point understand that it's not that simple so now I want to iterate over the named fields map um oh I need to iterate over the what attribute is what's the attribute called named rust format is really annoying here as well and if I iterate over that I guess I get just the fields probably and I want to quote that into a um let's do it like this that bracket is too far outside um let's get the field name field name equals field Dot I don't expect [Music] um named Fields always yeah a name so it's fine to panic there because we know that we are we have named Fields so the name should never be none and then we also have the fields type is feel DOT type for whatever reason I really don't like um shortening your names like that he said having the most terrible variable names ever okay um power [Music] with the parser and I want to try and pass it and then if passing fails we just support and then I can collect this into a token structure okay with rust format please stop removing my braces now and no it it won't why so annoying um yeah references are fine then we can unwrap on that okay um so that's all the struct field passing and then I guess I need to add a let's [Music] see yeah I guess if I do an assignment here then it might be happy rust format might be happy with me yeah there we go okay and then I want to quote again and I want to self um the field passing code goes in here and I think that's it for the order code at least this is really getting quite complex now [Music] um all right of course it needs to be the the variant I was wondering why we didn't need different here but of course this should be done like this and and then we can wrap that in in a pass optional but um this code now tries to pass other things in any order now let's move on to the more complicated cases like the unordered case um okay so now we need to um how do we do this so the cases can occur in any order um and I guess if one of them matches then none of the other matches right so we can never have um something like for example a or a a because then if we pass the value AAA or rather we pass this then it would be ambiguous and I think CSS passing is just never ambiguous so we should um yeah we should maybe keep a list of values that we are still missing um [Music] maybe this should actually be a parser function no no um [Music] I need to keep track of which options have already been passed and this also doesn't need to be super optimized I believe it kind of does me too okay but then we don't need to worry about performance too much for now okay then let um past feels equal none and we want to yeah this is this is fine for performance it doesn't matter too much and I have I want to that number of fields equal hashtag named Fields dots named then so that is the number of fields and in the beginning we have no Fields passed so everything is just not and this is a hashtag right and this all needs to go to a quote natural it's kind of confusing to see um rust code mixed in with the quote macro code kind of hard to distinguish it [Music] um okay so in the beginning we have no fields and then um uh for in zero two number of fields because we need to pass all the fields and then we want to iterate over all the values in the past fields fields located and I want to iterate of it simply so I also need to declare this as mutable and then I want to filter all of those out that are some editor none and yeah here dot is none I don't get the inlay hints that have come to rely on them quite a lot so now we should try pass that if that's some value to parser Powers optional value and we want to pass try and pass the type of the field at at the given index is that right oh yeah yeah so I I need to also do that compile time um pass fields pause field and this should just um try and pass code to try and pass each field office truck once porting early if passing six right and then if it succeeds if it's causing succeeds the value is written into the past feels array and um oh wait I no I think I'm over complicating this yeah I don't need to install this as a separate thing um I'm really confusing myself right now sorry I think my commentary is also getting kind of incoherent right I do need to unroll the for Loop because um right now I don't know which type I need to parse wait am I just no I can't even use the the array thing like that right because of course I'm storing different values in there so I just need to use okay I need to unroll everything um yeah um so let's write something like field initial conversation English fully every period is none AKA s not yet in past e um and then I want to iterate over our name fields feature and I want to enumerate it for convenience and um then I want to map this index field pair do I want another two two and I want to map it to field underscore index and this should of course be inside a quote macro field underscore index equals none uh so I guess I don't even need the field information in here 0.8 Fields dots names then I don't need to enumerate this then this can also become the number of fields consider adding white space here now I I want to create uh why is this not valid because I'm not I don't have an index I want to create a new variable name unknown literal prefix I want to create something like um field one step oh I'm just an idiot I am an idiot I'm a complete buffoon no it still doesn't work um maybe without the Alaska maybe it's a um I'm not sure this does what I want um I'm sure I'm not the first person with that issue press 12 to create new item how can I create hygienic identifier um okay so I can I guess I can create my new identifier um okay and is it stable by now it is not stable but I can I'm not scared of nightly compilers I mean the whole thing the whole browser Builds on nightly anyway so I guess I can use the new syntax I don't knew and I have a form performance um index and then the ident is does it not have uh how can I create an island an identifier now clock micro 2 does have and a span struct analyzer is just drunk why do you not like my code um of course I need parentheses around this part um takes two arguments but one argument was supplied you must closing my my parentheses I am closing too many of them that's the problem no function name def site right because I do need to enable a feature let's look at the documentation unstable features [Music] oh God this already sounds like a pain [Music] um [Music] okay let's just use the call side instead of the definition side I don't really care whether the um identifier ends up I really don't care do I not need to call Eternal range apparently I don't very nice and then I need to borrow here and now this can just become a field I did and I suppose I should also collect these in a separate vector foreign [Music] and that works now and now I don't want to iterate over the index anymore I want to iterate over the field items and this should be an island nice okay um then for each iteration I wait why are you why is everything red is it because of you this okay um so now I want to try and pass each field so that I need to write over a field items again do I need to iterate over the field items yes and I want to zip the named pls.net right and then and then I'm going to map this and I have a field items names and I want to map them and collect the results into a token stream too okay and then the next step is quote macro here again and don't like spaces after that and if we have some plus value is pars or the RS optional value by the way I'm I'm sorry for my like lack of high quality commentary right now but this is kind of really complicated to think about um so I kind of I'm kind of distracted I'm sorry for that so if we have a past value then first of all after that we want to break out of the auto for Loop uh no we want to continue um this for Loop here and before that we want to write to the field items and the field items should then be some um the field ident should be some of the parsed value that we just passed and now what exactly do we need to parse we need to pass the named name filed named fields I want to pass the name field I need I need to type first that's here to type named fear DOT type I want to take a reference of course so you can't move out of that [Music] either so we don't need to take the reference down here we do we do never mind apparently we do okay um and now I want to call Fields type parse awesome okay so um at this point and then um right if we haven't continued down here then we want to return an error pass error and let's also add a comment if we did not continue yet none of the appears Taurus successfully which is an error yes passed successfully which is an error so at this point down here um everything should be some because everything has been passed uh wait isn't this isn't right I need to first check um if the value even is none silent I've just gone and if it is not none then we shouldn't try and pause it again okay this is all building on the assumption that um that Fields can never be prefixes of each other so at any given point in time at any point in this for Loop only one of all the fields will successfully pass and all the others should fail okay um and now we can basically just return okay um no we want to return so uh variant and there we need another sub step field readout for lack of a better name again it's not great naming but I think this one is actually one of the better names okay um let's feel to create uh read out equal I want to iterate over the field items again and I I basically want to do the same thing as up here and um I want to map this once again with the field and then I want to collect the results to a token stream tool okay and what we want to add it to is um First Quality uh me um I need the field name field Dot and I don't want to have field name and field items and the same thing but again I can clean up the variable names later unwrap and I'm missing a pipe here and this needs ref of course okay and then we have the fields Name colon dot unwrap okay um I think that's pretty good right why are we not using the struct variance code oh oh right that's okay for now it's okay to not use this for now and then the um next one is the field filter models yeah the optional unordered and then there's no more to do because there's only those three options and I basically want to do the same thing but I don't want to panic I don't want to return an error down here if nothing passes and in that case I just want to break out of the loop and um assign the field so it's very similar and what can I reuse I can't really reuse the field readout but I can reuse the pass fields and this stuff is it worth it's um to separate those out um I guess I don't really even need to um I can do it like this I can handle them both in the same case because they are the same up to here and then even down here they're not that different if it comes frame constraints um optional and ordered if it's optional then we do this else so this is our old case and in the new case we simply don't want to unwrap here does it not imply or rather I should add the I I don't want a reference in here I want the entire thing huh why doesn't this work that's weird I thought it would work I mean I guess I can also borrow down here it's not the end of the world it's just kind of ugly okay so if it is optional then we do not want to unwrap and then let's also introduce a handle nothing cars case equals if trained is a field constraints optional unordered um if our heroes are optional then we are simply done passing so we want to break else um if our fields are not optional then this is an error and we need to erode about this really meta code metab programming at its best handle nothing fast case and then this needs to be oh wait oh this needs to be up here wow uh this code is quite something okay and uh one second let me quickly pause the recording sorry okay um I'm back sorry for the delay we're just going to continue where we left off um so now I need to use actually use the generated code for each of the different variants um so I guess I want to call this inside a pass optional value so I guess these should all return okay as a variant so we can properly handle the arrows this is okay two um and then now the the struct variance code is now a a code a piece of code that can try and pass destruct um the given struct yeah and or rather it's a collection oh no this isn't quite right um I need to add another layer of abstraction here um that pass struct and then this should have a semicolon at the end why do you not purse okay um and then I want to basically call closer but pass optional value with the pass instruct um and [Music] I need to think about this a little why does this not work let expressions are not supported here um I'm not trying to use a lead expression um I think I messed up the the brackets the curly braces at some point um that's the first block um this is the second block all right so I should uh put my stuff in there wait why are these parentheses this should be parentheses um and then I can move this down and hopefully you know it won't form it just yet why not do I need to add this so this is the sort of the underlying lead expression and now we don't get any errors but it also doesn't parse or at least rust format doesn't do anything why it's just indented own um so this gives us the pass struct I'm pretty sure that I mean rust format does something just not something very useful I was hoping it could maybe modify this a little but this is going to do it for now okay um so I want to pass the optional value and then if that returns some past value then I want to return itself um do we have the variant here stick variant um with the oh no actually I would want to just return the past value and I want to make it okay so we can use it outside another passing function and then I believe it's really not doing its thing right now but let's just include this um of course we can do it down here once rust analyzer just dead again I'm gonna restart it uh one thing at a time let's first uncomment this this Panic spiders panic because I did not declare these helper attributes that makes sense that's fair enough actually um so we need ordered unordered and optional unordered and it still panics not yet implemented um where is the right to do um to push I think I just want to break do not I mean I'm kind of done here um yeah if we have named Fields then we iterate over all the attributes yeah that's it don't need to panic there and then cannot find Value Pass struct in this scope where is there a pass struct s match constraint and we're not using that and because this should be a hashtag and not too curly braces and that still doesn't compile um wait why does why is this invalid comparison operators cannot be changed are we messing up some some kind of parsing stuff because I believe this should be perfectly valid rust code no am I stupid maybe it's we should fix that first I guess statement found outside of block um that is because we do not surround this by braces which we should do and proc macro derived produced unpausible tokens how did that happen um that shouldn't be possible we are always properly quoting where where is that Panic occurring here okay so maybe it is related to this wait am I just messing up this this index Rustin here I mean I rarely use track Fields because I usually just put a struct into um into an enum but then again I don't think I would mess up the syntax for that oh come on give me the give me the enum that I want enumerations yeah that's exactly how you do it but now I'm confused um I'm not trying to display a const argument [Music] um I don't really understand because whatever we add down here that shouldn't really affect uh the stuff that is produced by the CSS um parser macro should not affect the actual struct do that um that's kind of annoying do I get more information if I do cargo run uh this shouldn't cause a bug so maybe this is a compiler bug because this is very clearly valid rust code very very clearly um and it should be accepted as such but it did not panic before so let's let's try and figure out at what points stuff goes wrong so if I comment this out then it's fine but if I don't count it out then everything breaks oh that oh oh that might be because um oh because of the call side so the Diagnostics are just uh not correct we're just getting bad diagnostics from this um because something in here is not correct cargo exposed maybe I believe okay um test uh okay it's very big it's still a good Excel I think okay and now I want to look for um parsed fields for example should be some no um let's look for parsed keyword yeah uh-huh um so that's the color value that is the background color value that's the display value that's the one we're interested in um so we have two fields field zero none field one none right um past Fields as red white we have isn't that redundant we're never using past fields so I can remove that um [Music] wait where where do I even Define that where's this line coming from there it is so we don't need you anymore but this also shouldn't have caused any issues yeah it's just the Redundant line and then um apart from that we iterated over this two times and say if the first field is none then try and try and pass something empty well that's not correct um why do we try and pass nothing um we want the field type is it possible that the field type is just not existent [Music] um let's just Panic on the field type I'm sure they Implement debug at least there we go so let's um um cannot be formatted with what because it does not uh I mean either way um no either way this can't be right because um we need to add a space here um let's see no this just does not work for some reason why oh something else I just remembered is you can just either fix me for that if we are optional unordered verify verify that at least one values that is something that we should do or rather that we need to do okay um is this even like the code that I'm looking at it's not except this quote remove the wait this is these ones are also wrong twice it bar oh because I added um the full bar stuff right um does it still Panic if I only have power yeah it's still panics okay then let's maybe use that as a reduced test case I am so confused does it not resolve these these attributes [Music] um let's just play outside I just want this display value yeah right okay um that's the keyword parser and I guess the compiler can optimize this part out I don't care about that for now again um yeah this this seems broken that's definitely not right why are we even constructed bar anymore all right because we we have this right um but why does it fill in these types um I am confused does it does it work if I just do what it says and add these these ones here rust format immediately removes them okay um but I shouldn't even need to remove them okay first of all why can this not fail um why can this not fail so apparently we can't really deal with these types very well um what to say soon time it's one of those but what I really want no a type should be fine [Music] two toggles so I can convert this to tokens so what happens if I just for testing I mean the field type is obviously wrong right so what happens if I just panic and give myself the field type field type.2 token between rust analyzer is also that again what but it literally is oh feature printing um I think that's a debug feature on Sunrise I think I could just debug the type immediately um it's called extra trades when does this thing Implement imply debug extra trades okay so let's just for testing we can take this out later add the extra Trace feature and then we don't have to use to token stream and can simply Panic on the thing itself and hopefully that should give us some more information um we do not panic at all why do we not panic we're not hit this code path it is inside unordered or optional all right because right now we are in the in the order section in the order section and then let's add this here please Panic now so we get this path um generic argument type so that seems fine why does it not work I mean I've done something similar previously have I not for the value type code here it's type name parse oh but then type name was just an identifier in that case uh um so maybe I can't um um I want to see what this looks like as a token stream so let's add the printing feature and then and again I didn't want to use code two tokens okay um we have a token stress okay so first we have an identifier option great then we have this symbol and we have identify this by outside and we have a closing symbol is that not what we want um I'm trying to figure out what I'm doing wrong um so this can be any one of these uh-huh what's a type group I don't know um [Music] for whatever reason we can't use the type just as sort of a literal thing um for whatever reason that does not work although I think it should or maybe because do I need to do something like field type as CSS parse maybe this I'm not seeing any arrows anymore that can be good or that can be bad okay let's uh back a little and try to run it it does compile and um let's see if I let's remove this for a bit I mean at least it compiles now um okay so let me quickly explain what I believe the error was um I think that is I am in my code field type is only ever an enum or a abstract it's never a type like um for example a slice of u8s um but I think if it was a slice of your eights then you couldn't use this power syntax because that's that's not legal rust syntax um so I assumed that um so in this case quote just recognizes hey this could be this is not how you can use a type and so first I need to cast it to CSS parse to use the trade object or rather use it straight functions and then I can call parse on it and hopefully that was the only error and now it works fine let me see um okay so now it expects wait if it's ordered then it should never um if it's all that then it shouldn't be optional so all that then should just work like this okay um then let's try to wait or that means that they need to occur in that exact order yeah right right so it needs to be a display outside and display inside so let's try and pass block flow um display block flow and I just recognized that that can't work because we need to skip white space in between yeah white space is definitely going to be an issue um let's skip white space in between the struct fields as CSS bars oh no um the individual puzzles they should take care of white space for us so each call to parse here should um take care of Any Trail in white space let's see if that's actually the case um inside the keyword match pass optional value um yeah I do not correctly skip y space skip past keyword and then we can just return an error here and then we can return okay on parse keyboard and then I need the functions up here to no longer return an okay time it does still compile okay um unreachable statement what's an unreachable statement let's look at carb respond again and let's look at this play outside so some value in here is apparently unused um what value is unused oh it's unreachable unreachable statement not unused what is unreachable I mean I only changed this part here right um what part of this is unused because I can also simplify this part a little um okay and let's actually keep it this part as this okay um but why does this cause an error if I comment you out then then nothing is unused uh unreachable sorry I keep I keep forgetting about that um this oh this is unreachable no it's not oh um okay um why is something in here Andre triple it's in this play outside right no it's not in display outside it's in I'm just stupid it's in display value and I mean of course I can't find the unreachable part if it's inside another thing okay oh okay now that's that generates a warning because um whatever happens we return so that is quite an easy fix I just need to check in and basically we don't even want to generate the let's code here well actually I could um I think it that's auto-generated annotation that not does not um there's a compiler annotation that basically tells the compiler that it's Auto generated um where where did I put it might there might be one and don't derived so let's quickly look if I can find it in there automatically derived yeah there it is um I basically want to use that and that tells the compiler to more or less shut up and let me do my thing and the compiler promptly ignores it well that's not very nice automatically derived I think that that should cause the it to [Music] maybe not okay let's simplify this okay then let's um pass keywords equals and then actually automatically derived should cause it to be quiet about those things what does automatically derived mean should not be reported as unused okay um I think there was an an attribute that told it to not worry about unreachable code okay um automatically derived no standard no core like okay I mean I can't find it right now apparently okay um then let's just figure out how we can not generate this code if it's not necessary okay first of all when is it not necessary we don't need to generate any keyword code if the keywords is empty if uh keywords dot is empty then this should be a token stream two new and otherwise we want it to be this entire block and then now we want um Parts keywords then we need a semicolon here our rust format doesn't really play well with um quote unfortunately but I can deal with that okay and we don't get a warning anymore very nice and then maybe let's also make the naming scheme in here um coherent pass units values Maybe and this could be post struct variants yeah this could be past unit variants pass structure variance and pass unit variants at least we're getting some kind of consistency in the code base now with naming schemes okay um so you should compile now see if you run fine unknown CSS property name display all right we don't I haven't added it to the properties yet display property and this has a display value and I need a spec link for that right and then if we have a display then I want to call Self display display with display value pass oh right pause off then if it fails we want to abort okay does that work now oh that works fine that is so cool you can see um what I mean right here we have a properties array and that properties array contains a display property which has the property outside block and inside flow and if I were to if I were to switch those so if I were to say flow block then that should not work anymore because these are ordered properties so they need to be in an exact order yeah very nice so now we get an empty array because um no there's no valid rule each rule rather the one rule that we have contains an error can't be passed that is a very very cool okay then I believe we need to apply the same fix that we had previously with restifix one second here this one um we need to do the same trick for the unordered and optional unordered Fields as well so wherever we use the Fields type luckily not we don't use it that much we need to replace it with field type as CSS parse and this is very unhygienic because CSS paths could be overwritten by some other namespace but we're not going to care about that for now I don't want to worry about that okay um let's go into let's close some of this that we don't need and let's go into properties and then enable this one the optional unordered so each field in here is optional and we do panic expected the option of outside and we found an option of option of outside um that sounds like we just over that like we just wrapped in some uh ones too much so let's do a yoga currently spans to test the s and um display value okay that's clone that's debug and this is the CSS pass okay okay so actually let's let's comment all the uh the bar part oh no no it doesn't it doesn't even matter because the bar part should be further down if I'm not wrong yeah this is this is the power part and this is the actually complicated full part um okay so we have weird one and field zero is then an option and why does this pack um let's maybe add compiler annotations for the types just so we can be certain that they are what we expect them to be actually no never mind that's that's not trivial to do let's not do that I was trying to um to add a type annotation here so that way we can be sure that what this option contains but um let's not do that for now oh right right right right right right um we do not want to write there's no point in parsing this optional value um because so and we're trying to pass an optional value of an option and that doesn't make sense instead what we should do is um what we should do instead what should we do instead that's not so trivial I guess we just want the parse this could just go to this parser and then if this errors out then we of course also want to error out and if it is right I mean this can't can't error out because it's an option but um just add it there anyway compiler is going to optimize their notes um now we are up here and it's um try to execute it and it looks like we do compile now uh and we get outside clock inside some flow um okay so if we look at this again what we see now is that um first of all this is now not um determinate so because bar is lower down food gets passed first but otherwise bar would get passed first but now we have these um two values that are optional and unordered and we get some block some flow that is correct um but if I were to for example remove the flow then we should see some block and none some block and none that is correct and if I were to say flow block then we should see the one up here again so some blocks are flow oh that is beautiful that is amazing that is wonderful okay and then let's also check that something has parsed so let's go in here and if constraint is optional unordered ordered um I'm trying to differentiate this from the handle nothing first case let's handle every field none equals if we're optional and ordered okay um now let's let's call this um verify past value so if the um if we are an optional type then we want to verify that that all the fields are non-zero so how do we do that and of course otherwise we just want to not verify anything so return an empty talk stream talking stream two then we want to call this down here okay and um semicolon here and now we want to check if this is none and that is none and that is none of that as well um how do I how can I do this nicely foreign thing kind of thing just um okay and I want to sort of flatten download flatten um intersperse no I don't want to test for us uh I think fault might be correct fault takes to argument an initial value and a closure with two arguments and accumulator and an element there's a broken way to do this and there's the right way to do this in that and I'm going to choose the broken way to do this um because what I want to do is basically check um hey if uh one second if field zero that is none and Fields one dot is none and so on and then I want to panic but um there's no easy way to put an ampersand between all of these these uh individual conditionals but not before or after it but like what I can do is just put a true before it and then put a double Ampersand in before every field and that's kind of stupid but it also kind of works and so I'm fine with it um and then I just need to uh an initial value [Music] oh right there's an accumulate method no I think something like um what if I want to fold but I want to start with the initial first ad ah reduce reduce reduce um reduce reduce okay so I don't need to do my ugly hack I can just call I did this none and then say hey please reduce into um I need to provide it with a get accumulator e H the accumulated element and then I want to say quote at the accumulator and the e and hashtag e and then I don't need to collect this anymore I believe I can just do unwrap or positive implied default foreign tokenstream new um consider returning the local binding input initialization Bots um expected nothing found a token stream oh um let's all wheels are none and then I can do quotes if hashtag all fields are none then I want to panic no I want to I want to return an error pass error and then there should be a semicolon not a colon and this compiles this compiles okay it's just checked that I didn't break anything I did not and then let's see what happens if I don't give it any values um and it doesn't work anymore beautiful very nice um okay so that concludes the checks for optional and all that let's let's look at just unordered um I don't suppose there will be any bugs in there but let's just find out unordered and we panic [Music] why do we panic and test RS um I want to check for the display value right okay and why does this cause cause issues um expected display inside found option and display outside font option the expression has Type display site uh -huh oh here of course okay um I see two ways to fix this one of them is good one of them is not good hmm um how hard is it to get the first generic argument from a type or rather if we have a Time named fierce okay um if we have a type how hard is it to get the first generic argument of that type um guess type path that's what I usually consider segments no no I mean the generic do the generics not long in there uh and okay let's just go with the ugly solution for now it's not that great but it it works and that's good enough for now um basically we can't do this wait why is that full argument here a full comment [Music] basically if we are optional on order then we can do this otherwise uh should have copied that whole line my bad then we can do this otherwise we have to actually pass an optional value there um [Music] and this is not really pretty because the code up here shouldn't be the way it is let's just keep it that way past optional value press the optional value there it is and we want to pass that time and if that is valid then we do that okay that should be fine now and it does indeed Powers fine let's see what happens if I switch up the order block and that also works fine very nice um do I want to commit it the way it is right now and this is kind of spaghetti code but then again um it's not like I mean we're Auto generating a lot of rather complex code so I'm not sure if that's even a simpler way to do this I kind of dialed it Maybe everything together maybe we can add some explanatory comments these are the switch arms in a match block match is the word that we use in Rust but match arms in the match block um that map from a keyword fstr anding value type for example um just add something like this and then foreign Foo and I just noticed that I added this comment on the wrong part of the code because this one is actually fairly obvious and this should be up there on the match arms keyword matchup I believe it's called the app here okay this one is also quite simple hmm for each unit struct variant for exam called who contains type for each of those um types we try and pass the content type and if it succeeds return that variant with the parts value okay [Music] um I mean there's a lot more that could be done in here I'm not super happy with the code especially with this part wait am I just shooting myself in the foot here uh I think I am no wait um if we are optional unordered then we don't unwrap down here because it's fine for our values to not okay um okay so I keep confusing myself about this it's fine to not unwrap here because our values might not exist because of course they're optional um and then it's actually kind of fine to do it like this up here as well yeah I guess this isn't too bad I'm gonna run it one more time just to be sure okay nice um then let's make a commit of this I won't commit the changes inside properties for now wait what did I change about the parser oh I do have to add this but I'm not gonna commit the changes inside properties because there's a bunch of debug code in here and I can add the display value later off camera Maybe yeah don't need to do it right now okay um let's make a commit out of this I want to commit um CSS property derive what else did I change I want to remove the test file that I had that I made I want to also um commit the changes to the parcel CSS parts uh why not syntax I forgot these syntax folder and apart from that I think that's pretty much it the rest is either debug files that I want to keep around or just changes for testing cool then let's commit this um CSS CSS let's call it CSS the rifle just just shorthand stuff um pause more complex combinator values not create that message but either way um for examples of this refer to the implemented CSS properties um will be done in a later committee and let's also add a link to the spec component value combinators this allows us to express the CSS component value combinators as um rust types with annotations I want the link to the component value combinators that's the spec link I want the I want the slack um okay let's add this very cool cool um that was some of the heaviest meta programming code that I've written in quite a while I mean how long is this now 300 lines of generating rust code it's quite painful but um I think the result is okay and wait if we are up that's a fix me here and if we are optional unordered verify that at least one value has been parsed but I just did this this is literally what the code below right below the fixed meters get ads to derive and I meant that okay very cool then I think that's going to do it for today if you stuck around until the end then I thank you for watching and I hope you learned something new today see you all in a later video and bye
Info
Channel: Alaska
Views: 37
Rating: undefined out of 5
Keywords:
Id: RJTSrHINiMY
Channel Id: undefined
Length: 148min 56sec (8936 seconds)
Published: Sun May 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.